From 4feeab8c61334ec73172fa01cda951dafde2505f Mon Sep 17 00:00:00 2001 From: blacksirius Date: Sun, 3 Jun 2012 18:53:02 +0000 Subject: feature merge bs-coreoptimize->trunk: Atomic Operations, Threading, Spinlock implemnetation. [commit 1/2, windows will followup] - Added Abstractions for Atomic Operations (lock instructions.. windows guy's may now this as Interlocked* stuff ..) - Added Threading api abstraction for Pthread based OS's and Windows - Added Spinlock Implementation (uses CAS / if you need more informations - just read the source - its simple.) - Due to Interlocked(Compare)Exchange64 .. we now require at least i686 (Pentium Pro) for 32Bit Builds :) youll also may feel some performance improvements when using 32bit builsd due to "newer" minimal arch the compiler is now able to use CMOV's .... ================================================================ = Important Warning: ================================================================ Dont use threading at the moment athena is not threadsafe! you'll mess up everthing when accessing data from other threads .., no synchronization is provided. A way to process tasks asynchronously will come up after / with the new socket system. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16221 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/thread.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/common/thread.c (limited to 'src/common/thread.c') diff --git a/src/common/thread.c b/src/common/thread.c new file mode 100644 index 000000000..49accff4c --- /dev/null +++ b/src/common/thread.c @@ -0,0 +1,270 @@ + +#ifdef WIN32 +#include "../common/winapi.h" +#define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) +#define __thread __declspec( thread ) +#else +#include +#include +#include +#include +#include +#include +#endif + +#include "cbasetypes.h" +#include "malloc.h" +#include "showmsg.h" +#include "thread.h" + + +#define RA_THREADS_MAX 64 + +struct rAthread { + unsigned int myID; + + RATHREAD_PRIO prio; + rAthreadProc proc; + void *param; + + #ifdef WIN32 + HANDLE hThread; + #else + pthread_t hThread; + #endif +}; + + +__thread int g_rathread_ID = -1; + + +/// +/// Subystem Code +/// +static struct rAthread l_threads[RA_THREADS_MAX]; + +void rathread_init(){ + register unsigned int i; + memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) ); + + for(i = 0; i < RA_THREADS_MAX; i++){ + l_threads[i].myID = i; + } + + // now lets init thread id 0, which represnts the main thread + g_rathread_ID = 0; + l_threads[0].prio = RAT_PRIO_NORMAL; + l_threads[0].proc = (rAthreadProc)0xDEADCAFE; + +}//end: rathread_init() + + + +void rathread_final(){ + register unsigned int i; + + // Unterminated Threads Left? + // Should'nt happen .. + // Kill 'em all! + // + for(i = 1; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc != NULL){ + ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); + rathread_destroy(&l_threads[i]); + } + } + + +}//end: rathread_final() + + + +// gets called whenever a thread terminated .. +static void rat_thread_terminated( rAthread handle ){ + + int id_backup = handle->myID; + + // Simply set all members to 0 (except the id) + memset(handle, 0x00, sizeof(struct rAthread)); + + handle->myID = id_backup; // done ;) + +}//end: rat_thread_terminated() + +#ifdef WIN32 +DWORD WINAPI _raThreadMainRedirector(LPVOID p){ +#else +static void *_raThreadMainRedirector( void *p ){ + sigset_t set; // on Posix Thread platforms +#endif + void *ret; + + // Update myID @ TLS to right id. + g_rathread_ID = ((rAthread)p)->myID; + +#ifndef WIN32 + // When using posix threads + // the threads inherits the Signal mask from the thread which's spawned + // this thread + // so we've to block everything we dont care about. + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + +#endif + + + ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ; + +#ifdef WIN32 + CloseHandle( ((rAthread)p)->hThread ); +#endif + + rat_thread_terminated( (rAthread)p ); +#ifdef WIN32 + return (DWORD)ret; +#else + return ret; +#endif +}//end: _raThreadMainRedirector() + + + + + +/// +/// API Level +/// +rAthread rathread_create( rAthreadProc entryPoint, void *param ){ + return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL ); +}//end: rathread_create() + + +rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){ +#ifndef WIN32 + pthread_attr_t attr; +#endif + size_t tmp; + unsigned int i; + rAthread handle = NULL; + + + // given stacksize aligned to systems pagesize? + tmp = szStack % getpagesize(); + if(tmp != 0) + szStack += tmp; + + + // Get a free Thread Slot. + for(i = 0; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc == NULL){ + handle = &l_threads[i]; + break; + } + } + + if(handle == NULL){ + ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); + return NULL; + } + + + + handle->proc = entryPoint; + handle->param = param; + +#ifdef WIN32 + handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL); +#else + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, szStack); + + if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){ + handle->proc = NULL; + handle->param = NULL; + return NULL; + } + pthread_attr_destroy(&attr); +#endif + + rathread_prio_set( handle, prio ); + + return handle; +}//end: rathread_createEx + + +void rathread_destroy ( rAthread handle ){ +#ifdef WIN32 + if( TerminateThread(handle->hThread, 0) != FALSE){ + CloseHandle(handle->hThread); + rat_thread_terminated(handle); + } +#else + if( pthread_cancel( handle->hThread ) == 0){ + + // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. + // + pthread_join( handle->hThread, NULL ); + + // Tell our manager to release ressources ;) + rat_thread_terminated(handle); + } +#endif +}//end: rathread_destroy() + +rAthread rathread_self( ){ + rAthread handle = &l_threads[g_rathread_ID]; + + if(handle->proc != NULL) // entry point set, so its used! + return handle; + + return NULL; +}//end: rathread_self() + + +int rathread_get_tid(){ + + return g_rathread_ID; + +}//end: rathread_get_tid() + + +bool rathread_wait( rAthread handle, void* *out_exitCode ){ + + // Hint: + // no thread data cleanup routine call here! + // its managed by the callProxy itself.. + // +#ifdef WIN32 + WaitForSingleObject(handle->hThread, INFINITE); + return true; +#else + if(pthread_join(handle->hThread, out_exitCode) == 0) + return true; + return false; +#endif + +}//end: rathread_wait() + + +void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){ + handle->prio = RAT_PRIO_NORMAL; + //@TODO +}//end: rathread_prio_set() + + +RATHREAD_PRIO rathread_prio_get( rAthread handle){ + return handle->prio; +}//end: rathread_prio_get() + + +void rathread_yield(){ +#ifdef WIN32 + SwitchToThread(); +#else + sched_yield(); +#endif +}//end: rathread_yield() -- cgit v1.2.3-70-g09d2 From d6087662f5c19b693a000126d02ced43aad5d2f7 Mon Sep 17 00:00:00 2001 From: blacksirius Date: Sun, 3 Jun 2012 20:09:39 +0000 Subject: thread api: added support for platforms without TLS (Thread Local Storage) support (usually older OSX llvm versions ..) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16226 54d463be-8e91-2dee-dedb-b68131a5f0ec --- configure | 44 +++++++++++++++++++++++++++++++++++++++++++- configure.in | 24 ++++++++++++++++++++++++ src/common/thread.c | 42 +++++++++++++++++++++++++++++++++++++++++- src/common/thread.h | 3 ++- 4 files changed, 110 insertions(+), 3 deletions(-) (limited to 'src/common/thread.c') diff --git a/configure b/configure index 7cb751351..67d416776 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 16203 . +# From configure.in Revision: 16221 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67. # @@ -4708,6 +4708,48 @@ fi +# +# Check if CC supports __thread attribute (Thread Local Storage) +# (Usually our OSX friends 're lacking support of it in older llvm versions ..) +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports __thread specifier (TLS)" >&5 +$as_echo_n "checking whether $CC supports __thread specifier (TLS)... " >&6; } +if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5 ; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + __thread int g_Test = -1; + + int main(int argc, char **argv){ + g_Test = 0; + return g_Test; + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$CFLAGS -DHAS_TLS" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-parameter" >&5 $as_echo_n "checking whether $CC supports -Wno-unused-parameter... " >&6; } OLD_CFLAGS="$CFLAGS" diff --git a/configure.in b/configure.in index 2d3df1ce2..e602db19f 100644 --- a/configure.in +++ b/configure.in @@ -363,6 +363,30 @@ AC_RUN_IFELSE( ) +# +# Check if CC supports __thread attribute (Thread Local Storage) +# (Usually our OSX friends 're lacking support of it in older llvm versions ..) +# +AC_MSG_CHECKING([whether $CC supports __thread specifier (TLS)]) +AC_RUN_IFELSE( + [ + __thread int g_Test = -1; + + int main(int argc, char **argv){ + g_Test = 0; + return g_Test; + } + ], + [ + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -DHAS_TLS" + ], + [ + AC_MSG_RESULT([no]) + ] +) + + AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter]) OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-parameter" diff --git a/src/common/thread.c b/src/common/thread.c index 49accff4c..728c6c66a 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -17,6 +17,11 @@ #include "showmsg.h" #include "thread.h" +// When Compiling using MSC (on win32..) we know we have support in any case! +#ifdef _MSC_VER +#define HAS_TLS +#endif + #define RA_THREADS_MAX 64 @@ -35,7 +40,9 @@ struct rAthread { }; +#ifdef HAS_TLS __thread int g_rathread_ID = -1; +#endif /// @@ -52,7 +59,9 @@ void rathread_init(){ } // now lets init thread id 0, which represnts the main thread +#ifdef HAS_TLS g_rathread_ID = 0; +#endif l_threads[0].prio = RAT_PRIO_NORMAL; l_threads[0].proc = (rAthreadProc)0xDEADCAFE; @@ -100,7 +109,9 @@ static void *_raThreadMainRedirector( void *p ){ void *ret; // Update myID @ TLS to right id. +#ifdef HAS_TLS g_rathread_ID = ((rAthread)p)->myID; +#endif #ifndef WIN32 // When using posix threads @@ -216,18 +227,47 @@ void rathread_destroy ( rAthread handle ){ }//end: rathread_destroy() rAthread rathread_self( ){ +#ifdef HAS_TLS rAthread handle = &l_threads[g_rathread_ID]; if(handle->proc != NULL) // entry point set, so its used! return handle; +#else + // .. so no tls means we have to search the thread by its api-handle .. + int i; + + #ifdef WIN32 + HANDLE hSelf; + hSelf = GetCurrent = GetCurrentThread(); + #else + pthread_t hSelf; + hSelf = pthread_self(); + #endif + + for(i = 0; i < RA_THREADS_MAX; i++){ + if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) + return &l_threads[i]; + } + +#endif return NULL; }//end: rathread_self() int rathread_get_tid(){ - + +#ifdef HAS_TLS return g_rathread_ID; +#else + // todo + #ifdef WIN32 + return (int)GetCurrentThreadId(); + #else + return (int)pthread_self(); + #endif + +#endif }//end: rathread_get_tid() diff --git a/src/common/thread.h b/src/common/thread.h index d4027811f..8d3441868 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -62,7 +62,8 @@ rAthread rathread_self( ); /** * Returns own thrad id (TID) * - * @note this is not the operating system THREAD ID! + * @note this is an unique identifier for the calling thread, and + * depends on platfrom / compiler, and may not be the systems Thread ID! * * @return -1 when fails, otherwise >= 0 */ -- cgit v1.2.3-70-g09d2 From e85c28ce148e0740697c76e9751b0d9cacbe67d1 Mon Sep 17 00:00:00 2001 From: blacksirius Date: Sun, 10 Jun 2012 16:04:24 +0000 Subject: - added some missing copyrights - merged (bs-coreoptimize->trunk) generic athena style configuration parser (raconf) - merged (bs-coreoptimize->trunk) threadsafe memory pool (mempool) [i need it for the new 'socket' system] - set svn:eol-style property on newer files were it was missing git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16263 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/CMakeLists.txt | 6 + src/common/Makefile.in | 2 +- src/common/atomic.h | 3 + src/common/core.c | 5 +- src/common/mempool.c | 562 ++++++++++++++++++++++++++++++++++++++++++++ src/common/mempool.h | 100 ++++++++ src/common/mutex.c | 2 + src/common/mutex.h | 3 + src/common/raconf.c | 584 ++++++++++++++++++++++++++++++++++++++++++++++ src/common/raconf.h | 59 +++++ src/common/thread.c | 7 + src/common/thread.h | 3 + 12 files changed, 1333 insertions(+), 3 deletions(-) create mode 100644 src/common/mempool.c create mode 100644 src/common/mempool.h create mode 100644 src/common/raconf.c create mode 100644 src/common/raconf.h (limited to 'src/common/thread.c') diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 46c32c236..b32c33611 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -79,6 +79,9 @@ set( COMMON_BASE_HEADERS "${COMMON_SOURCE_DIR}/atomic.h" "${COMMON_SOURCE_DIR}/spinlock.h" "${COMMON_SOURCE_DIR}/thread.h" + "${COMMON_SOURCE_DIR}/mutex.h" + "${COMMON_SOURCE_DIR}/raconf.h" + "${COMMON_SOURCE_DIR}/mempool.h" ${LIBCONFIG_HEADERS} # needed by conf.h/showmsg.h CACHE INTERNAL "common_base headers" ) set( COMMON_BASE_SOURCES @@ -100,6 +103,9 @@ set( COMMON_BASE_SOURCES "${COMMON_SOURCE_DIR}/timer.c" "${COMMON_SOURCE_DIR}/utils.c" "${COMMON_SOURCE_DIR}/thread.c" + "${COMMON_SOURCE_DIR}/mutex.c" + "${COMMON_SOURCE_DIR}/mempool.c" + "${COMMON_SOURCE_DIR}/raconf.c" ${LIBCONFIG_SOURCES} # needed by conf.c/showmsg.c CACHE INTERNAL "common_base sources" ) set( COMMON_BASE_INCLUDE_DIRS diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 3f03982d7..b6713b6a1 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -3,7 +3,7 @@ COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_al obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \ - obj_all/conf.o obj_all/thread.o obj_all/mutex.o + obj_all/conf.o obj_all/thread.o obj_all/mutex.o obj_all/raconf.o obj_all/mempool.o COMMON_H = $(shell ls ../common/*.h) diff --git a/src/common/atomic.h b/src/common/atomic.h index 7a9e8c4cc..c09d8d386 100644 --- a/src/common/atomic.h +++ b/src/common/atomic.h @@ -1,3 +1,6 @@ +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + #ifndef _rA_ATOMIC_H_ #define _rA_ATOMIC_H_ diff --git a/src/common/core.c b/src/common/core.c index 4e276fcdc..2923b4de7 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -10,6 +10,7 @@ #include "../common/socket.h" #include "../common/timer.h" #include "../common/thread.h" +#include "../common/mempool.h" #endif #include @@ -280,7 +281,7 @@ int main (int argc, char **argv) usercheck(); rathread_init(); - + mempool_init(); db_init(); signals_init(); @@ -306,7 +307,7 @@ int main (int argc, char **argv) timer_final(); socket_final(); db_final(); - + mempool_final(); rathread_final(); #endif diff --git a/src/common/mempool.c b/src/common/mempool.c new file mode 100644 index 000000000..ab401f5e0 --- /dev/null +++ b/src/common/mempool.c @@ -0,0 +1,562 @@ + +// +// Memory Pool Implementation (Threadsafe) +// +// +// Author: Florian Wilkemeyer +// +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// +// + +#include +#include +#include +#include + +#ifdef WIN32 +#include "../common/winapi.h" +#else +#include +#endif + +#include "../common/cbasetypes.h" +#include "../common/showmsg.h" +#include "../common/mempool.h" +#include "../common/atomic.h" +#include "../common/spinlock.h" +#include "../common/thread.h" +#include "../common/malloc.h" +#include "../common/mutex.h" + +#define ALIGN16 ra_align(16) +#define ALIGN_TO(x, a) (x + ( a - ( x % a) ) ) +#define ALIGN_TO_16(x) ALIGN_TO(x, 16) + +#undef MEMPOOL_DEBUG +#define MEMPOOLASSERT + + +#define NODE_TO_DATA(x) ( ((char*)x) + sizeof(struct node) ) +#define DATA_TO_NODE(x) ( (struct node*)(((char*)x) - sizeof(struct node)) ) +struct ra_align(16) node{ + void *next; + void *segment; +#ifdef MEMPOOLASSERT + bool used; + uint64 magic; + #define NODE_MAGIC 0xBEEF00EAEACAFE07ll +#endif +}; + + +// The Pointer to this struct is the base address of the segment itself. +struct pool_segment{ + mempool pool; // pool, this segment belongs to + struct pool_segment *next; + int64 num_nodes_total; + int64 num_bytes; +}; + + +struct mempool{ + // Settings + char *name; + uint64 elem_size; + uint64 elem_realloc_step; + int64 elem_realloc_thresh; + + // Callbacks that get called for every node that gets allocated + // Example usage: initialization of mutex/lock for each node. + memPoolOnNodeAllocationProc onalloc; + memPoolOnNodeDeallocationProc ondealloc; + + // Locks + SPIN_LOCK segmentLock; + SPIN_LOCK nodeLock; + + + // Internal + struct pool_segment *segments; + struct node *free_list; + + volatile int64 num_nodes_total; + volatile int64 num_nodes_free; + + volatile int64 num_segments; + volatile int64 num_bytes_total; + + volatile int64 peak_nodes_used; // Peak Node Usage + volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) + + // list (used for global management such as allocator..) + struct mempool *next; +} ra_align(8); // Dont touch the alignment, otherwise interlocked functions are broken .. + + +/// +// Implementation: +// +static void segment_allocate_add(mempool p, uint64 count); + +static SPIN_LOCK l_mempoolListLock; +static mempool l_mempoolList = NULL; +static rAthread l_async_thread = NULL; +static ramutex l_async_lock = NULL; +static racond l_async_cond = NULL; +static volatile int32 l_async_terminate = 0; + +static void *mempool_async_allocator(void *x){ + mempool p; + + + while(1){ + if(l_async_terminate > 0) + break; + + EnterSpinLock(&l_mempoolListLock); + + for(p = l_mempoolList; p != NULL; p = p->next){ + + if(p->num_nodes_free < p->elem_realloc_thresh){ + // add new segment. + segment_allocate_add(p, p->elem_realloc_step); + // increase stats counter + InterlockedIncrement64(&p->num_realloc_events); + } + + } + + LeaveSpinLock(&l_mempoolListLock); + + ramutex_lock( l_async_lock ); + racond_wait( l_async_cond, l_async_lock, -1 ); + ramutex_unlock( l_async_lock ); + } + + + return NULL; +}//end: mempool_async_allocator() + + +void mempool_init(){ + + if(sizeof(struct node)%16 != 0 ){ + ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); + exit(EXIT_FAILURE); + } + + // Global List start + InitializeSpinLock(&l_mempoolListLock); + l_mempoolList = NULL; + + // Initialize mutex + stuff needed for async allocator worker. + l_async_terminate = 0; + l_async_lock = ramutex_create(); + l_async_cond = racond_create(); + + l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 512*1024, RAT_PRIO_NORMAL); + if(l_async_thread == NULL){ + ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); + exit(EXIT_FAILURE); + } + +}//end: mempool_init() + + +void mempool_final(){ + mempool p, pn; + + ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); + + // Terminate worker / wait until its terminated. + InterlockedIncrement(&l_async_terminate); + racond_signal(l_async_cond); + rathread_wait(l_async_thread, NULL); + + // Destroy cond var and mutex. + racond_destroy( l_async_cond ); + ramutex_destroy( l_async_lock ); + + // Free remaining mempools + // ((bugged code! this should halppen, every mempool should + // be freed by the subsystem that has allocated it.) + // + EnterSpinLock(&l_mempoolListLock); + p = l_mempoolList; + while(1){ + if(p == NULL) + break; + + pn = p->next; + + ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); + mempool_destroy(p); + + p = pn; + } + LeaveSpinLock(&l_mempoolListLock); + +}//end: mempool_final() + + +static void segment_allocate_add(mempool p, uint64 count){ + + // Required Memory: + // sz( segment ) + // count * sz( real_node_size ) + // + // where real node size is: + // ALIGN_TO_16( sz( node ) ) + p->elem_size + // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) + // + size_t total_sz; + struct pool_segment *seg = NULL; + struct node *nodeList = NULL; + struct node *node = NULL; + char *ptr = NULL; + uint64 i; + + total_sz = ALIGN_TO_16( sizeof(struct pool_segment) ) + + ( (size_t)count * (sizeof(struct node) + (size_t)p->elem_size) ) ; + +#ifdef MEMPOOL_DEBUG + ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); +#endif + + // allocate! (spin forever until weve got the memory.) + i=0; + while(1){ + ptr = (char*)aMalloc(total_sz); + if(ptr != NULL) break; + + i++; // increase failcount. + if(!(i & 7)){ + ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); +#ifdef WIN32 + Sleep(1000); +#else + sleep(1); +#endif + }else{ + rathread_yield(); /// allow/force vuln. ctxswitch + } + }//endwhile: allocation spinloop. + + // Clear Memory. + memset(ptr, 0x00, total_sz); + + // Initialize segment struct. + seg = (struct pool_segment*)ptr; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + + seg->pool = p; + seg->num_nodes_total = count; + seg->num_bytes = total_sz; + + + // Initialze nodes! + nodeList = NULL; + for(i = 0; i < count; i++){ + node = (struct node*)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; + + node->segment = seg; +#ifdef MEMPOOLASSERT + node->used = false; + node->magic = NODE_MAGIC; +#endif + + if(p->onalloc != NULL) p->onalloc( NODE_TO_DATA(node) ); + + node->next = nodeList; + nodeList = node; + } + + + + // Link in Segment. + EnterSpinLock(&p->segmentLock); + seg->next = p->segments; + p->segments = seg; + LeaveSpinLock(&p->segmentLock); + + // Link in Nodes + EnterSpinLock(&p->nodeLock); + nodeList->next = p->free_list; + p->free_list = nodeList; + LeaveSpinLock(&p->nodeLock); + + + // Increase Stats: + InterlockedExchangeAdd64(&p->num_nodes_total, count); + InterlockedExchangeAdd64(&p->num_nodes_free, count); + InterlockedIncrement64(&p->num_segments); + InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); + +}//end: segment_allocate_add() + + +mempool mempool_create(const char *name, + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc){ + //.. + uint64 realloc_thresh; + mempool pool; + pool = (mempool)aCalloc( 1, sizeof(struct mempool) ); + + if(pool == NULL){ + ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool) ); + exit(EXIT_FAILURE); + } + + // Check minimum initial count / realloc count requirements. + if(initial_count < 50) + initial_count = 50; + if(realloc_count < 50) + realloc_count = 50; + + // Set Reallocation threshold to 5% of realloc_count, at least 10. + realloc_thresh = (realloc_count/100)*5; // + if(realloc_thresh < 10) + realloc_thresh = 10; + + // Initialize members.. + pool->name = aStrdup(name); + pool->elem_size = ALIGN_TO_16(elem_size); + pool->elem_realloc_step = realloc_count; + pool->elem_realloc_thresh = realloc_thresh; + pool->onalloc = onNodeAlloc; + pool->ondealloc = onNodeDealloc; + + InitializeSpinLock(&pool->segmentLock); + InitializeSpinLock(&pool->nodeLock); + + // Initial Statistic values: + pool->num_nodes_total = 0; + pool->num_nodes_free = 0; + pool->num_segments = 0; + pool->num_bytes_total = 0; + pool->peak_nodes_used = 0; + pool->num_realloc_events = 0; + + // +#ifdef MEMPOOL_DEBUG + ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); +#endif + + // Allocate first segment directly :) + segment_allocate_add(pool, initial_count); + + + // Add Pool to the global pool list + EnterSpinLock(&l_mempoolListLock); + pool->next = l_mempoolList; + l_mempoolList = pool; + LeaveSpinLock(&l_mempoolListLock); + + + return pool; +}//end: mempool_create() + + +void mempool_destroy(mempool p){ + struct pool_segment *seg, *segnext; + struct node *niter; + mempool piter, pprev; + char *ptr; + int64 i; + +#ifdef MEMPOOL_DEBUG + ShowDebug("Mempool [%s] Destroy\n", p->name); +#endif + + // Unlink from global list. + EnterSpinLock(&l_mempoolListLock); + piter = l_mempoolList; + pprev = l_mempoolList; + while(1){ + if(piter == NULL) + break; + + + if(piter == p){ + // unlink from list, + // + if(pprev == l_mempoolList){ + // this (p) is list begin. so set next as head. + l_mempoolList = p->next; + }else{ + // replace prevs next wuth our next. + pprev->next = p->next; + } + break; + } + + pprev = piter; + piter = piter->next; + } + + p->next = NULL; + LeaveSpinLock(&l_mempoolListLock); + + + // Get both locks. + EnterSpinLock(&p->segmentLock); + EnterSpinLock(&p->nodeLock); + + + if(p->num_nodes_free != p->num_nodes_total) + ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free) ); + + // Free All Segments (this will also free all nodes) + // The segment pointer is the base pointer to the whole segment. + seg = p->segments; + while(1){ + if(seg == NULL) + break; + + segnext = seg->next; + + // .. + if(p->ondealloc != NULL){ + // walk over the segment, and call dealloc callback! + ptr = (char*)seg; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + for(i = 0; i < seg->num_nodes_total; i++){ + niter = (struct node*)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; +#ifdef MEMPOOLASSERT + if(niter->magic != NODE_MAGIC){ + ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); + continue; + } +#endif + + p->ondealloc( NODE_TO_DATA(niter) ); + + + } + }//endif: ondealloc callback? + + // simple .. + aFree(seg); + + seg = segnext; + } + + // Clear node ptr + p->free_list = NULL; + InterlockedExchange64(&p->num_nodes_free, 0); + InterlockedExchange64(&p->num_nodes_total, 0); + InterlockedExchange64(&p->num_segments, 0); + InterlockedExchange64(&p->num_bytes_total, 0); + + LeaveSpinLock(&p->nodeLock); + LeaveSpinLock(&p->segmentLock); + + // Free pool itself :D + aFree(p->name); + aFree(p); + +}//end: mempool_destroy() + + +void *mempool_node_get(mempool p){ + struct node *node; + int64 num_used; + + if(p->num_nodes_free < p->elem_realloc_thresh) + racond_signal(l_async_cond); + + while(1){ + + EnterSpinLock(&p->nodeLock); + + node = p->free_list; + if(node != NULL) + p->free_list = node->next; + + LeaveSpinLock(&p->nodeLock); + + if(node != NULL) + break; + + rathread_yield(); + } + + InterlockedDecrement64(&p->num_nodes_free); + + // Update peak value + num_used = (p->num_nodes_total - p->num_nodes_free); + if(num_used > p->peak_nodes_used){ + InterlockedExchange64(&p->peak_nodes_used, num_used); + } + +#ifdef MEMPOOLASSERT + node->used = true; +#endif + + return NODE_TO_DATA(node); +}//end: mempool_node_get() + + +void mempool_node_put(mempool p, void *data){ + struct node *node; + + node = DATA_TO_NODE(data); +#ifdef MEMPOOLASSERT + if(node->magic != NODE_MAGIC){ + ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); + return; // lost, + } + + { + struct pool_segment *node_seg = node->segment; + if(node_seg->pool != p){ + ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); + return; + } + } + + // reset used flag. + node->used = false; +#endif + + // + EnterSpinLock(&p->nodeLock); + node->next = p->free_list; + p->free_list = node; + LeaveSpinLock(&p->nodeLock); + + InterlockedIncrement64(&p->num_nodes_free); + +}//end: mempool_node_put() + + +mempool_stats mempool_get_stats(mempool pool){ + mempool_stats stats; + + // initialize all with zeros + memset(&stats, 0x00, sizeof(mempool_stats)); + + stats.num_nodes_total = pool->num_nodes_total; + stats.num_nodes_free = pool->num_nodes_free; + stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); + stats.num_segments = pool->num_segments; + stats.num_realloc_events= pool->num_realloc_events; + stats.peak_nodes_used = pool->peak_nodes_used; + stats.num_bytes_total = pool->num_bytes_total; + + // Pushing such a large block over the stack as return value isnt nice + // but lazy :) and should be okay in this case (Stats / Debug..) + // if you dont like it - feel free and refactor it. + return stats; +}//end: mempool_get_stats() + diff --git a/src/common/mempool.h b/src/common/mempool.h new file mode 100644 index 000000000..aeaebe7fe --- /dev/null +++ b/src/common/mempool.h @@ -0,0 +1,100 @@ +#ifndef _rA_MEMPOOL_H_ +#define _rA_MEMPOOL_H_ + +#include "../common/cbasetypes.h" + +typedef struct mempool *mempool; + +typedef void (*memPoolOnNodeAllocationProc)(void *ptr); +typedef void (*memPoolOnNodeDeallocationProc)(void *ptr); + +typedef struct mempool_stats{ + int64 num_nodes_total; + int64 num_nodes_free; + int64 num_nodes_used; + + int64 num_segments; + int64 num_realloc_events; + + int64 peak_nodes_used; + + int64 num_bytes_total; +} mempool_stats; + + +// +void mempool_init(); +void mempool_final(); + + +/** + * Creates a new Mempool + * + * @param name - Name of the pool (used for debug / error messages) + * @param elem_size - size of each element + * @param initial_count - preallocation count + * @param realloc_count - #no of nodes being allocated when pool is running empty. + * @param onNodeAlloc - Node Allocation callback (see @note!) + * @param onNodeDealloc - Node Deallocation callback (see @note!) + * + * @note: + * The onNode(De)alloc callbacks are only called once during segment allocation + * (pool initialization / rallocation ) + * you can use this callbacks for example to initlaize a mutex or somethingelse + * you definitly need during runtime + * + * @return not NULL + */ +mempool mempool_create(const char *name, + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc); + + +/** + * Destroys a Mempool + * + * @param pool - the mempool to destroy + * + * @note: + * Everything gets deallocated, regardless if everything was freed properly! + * So you have to ensure that all references are cleared properly! + */ +void mempool_destroy(mempool pool); + + +/** + * Gets a new / empty node from the given mempool. + * + * @param pool - the pool to get an empty node from. + * + * @return Address of empty Node + */ +void *mempool_node_get(mempool pool); + + +/** + * Returns the given node to the given mempool + * + * @param pool - the pool to put the node, to + * @param node - the node to return + */ +void mempool_node_put(mempool pool, void *node); + + +/** + * Returns Statistics for the given mempool + * + * @param pool - the pool to get thats for + * + * @note: i dont like pushing masses of values over the stack, too - but its lazy and okay for stats. (blacksirius) + * + * @return stats struct + */ +mempool_stats mempool_get_stats(mempool pool); + + +#endif diff --git a/src/common/mutex.c b/src/common/mutex.c index 874b81fa2..367574248 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -1,3 +1,5 @@ +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder #ifdef WIN32 #include "../common/winapi.h" diff --git a/src/common/mutex.h b/src/common/mutex.h index 4a32bcc8a..1999627cd 100644 --- a/src/common/mutex.h +++ b/src/common/mutex.h @@ -1,3 +1,6 @@ +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + #ifndef _rA_MUTEX_H_ #define _rA_MUTEX_H_ diff --git a/src/common/raconf.c b/src/common/raconf.c new file mode 100644 index 000000000..2703560ff --- /dev/null +++ b/src/common/raconf.c @@ -0,0 +1,584 @@ +// +// Athena style config parser +// (would be better to have "one" implementation instead of .. 4 :) +// +// +// Author: Florian Wilkemeyer +// +// Copyright (c) RAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// + + +#include +#include +#include + +#include "../common/cbasetypes.h" +#include "../common/showmsg.h" +#include "../common/db.h" +#include "../common/malloc.h" + +#include "../common/raconf.h" + +#define SECTION_LEN 32 +#define VARNAME_LEN 64 + +struct raconf { + DBMap *db; +}; + + +struct conf_value{ + int64 intval; + bool bval; + double floatval; + size_t strval_len; // not includung \0 + char strval[16]; +}; + + + +static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ + struct conf_value *v; + char *p; + size_t sz; + + sz = sizeof(struct conf_value); + if(val_len >= sizeof(v->strval)) + sz += (val_len - sizeof(v->strval) + 1); + + v = (struct conf_value*)aCalloc(1, sizeof(struct conf_value)); + if(v == NULL){ + ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); + return NULL; + } + + memcpy(v->strval, val, val_len); + v->strval[val_len+1] = '\0'; + v->strval_len = val_len; + + + // Parse boolean value: + if((val_len == 4) && (strncmpi("true", val, 4) == 0)) + v->bval = true; + else if((val_len == 3) && (strncmpi("yes", val, 3) == 0)) + v->bval = true; + else if((val_len == 3) && (strncmpi("oui", val, 3) == 0)) + v->bval = true; + else if((val_len == 2) && (strncmpi("si", val, 2) == 0)) + v->bval = true; + else if((val_len == 2) && (strncmpi("ja", val, 2) == 0)) + v->bval = true; + else if((val_len == 1) && (*val == '1')) + v->bval = true; + else if((val_len == 5) && (strncmpi("false", val, 5) == 0)) + v->bval = false; + else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if((val_len == 3) && (strncmpi("non", val, 3) == 0)) + v->bval = false; + else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if((val_len == 4) && (strncmpi("nein", val, 4) == 0)) + v->bval = false; + else if((val_len == 1) && (*val == '0')) + v->bval = false; + else + v->bval = false; // assume false. + + // Parse number + // Supported formats: + // prefix: 0x hex . + // postix: h for hex + // b for bin (dual) + if( (val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x')) ){//HEX! + if(val[val_len] == 'h'){ + val[val_len]= '\0'; + v->intval = strtoull(val, NULL, 16); + val[val_len] = 'h'; + }else + v->intval = strtoull(&val[2], NULL, 16); + }else if( val_len >= 1 && (val[val_len] == 'b') ){ //BIN + val[val_len] = '\0'; + v->intval = strtoull(val, NULL, 2); + val[val_len] = 'b'; + }else if( *val >='0' && *val <= '9'){ // begins with normal digit, so assume its dec. + // is it float? + bool is_float = false; + + for(p = val; *p != '\0'; p++){ + if(*p == '.'){ + v->floatval = strtod(val, NULL); + v->intval = (int64) v->floatval; + is_float = true; + break; + } + } + + if(is_float == false){ + v->intval = strtoull(val, NULL, 10); + v->floatval = (double) v->intval; + } + }else{ + // Everything else: lets use boolean for fallback + if(v->bval == true) + v->intval = 1; + else + v->intval = 0; + } + + return v; +}//end: makeValue() + + +static bool configParse(raconf inst, const char *fileName){ + FILE *fp; + char line[4096]; + char currentSection[SECTION_LEN]; + char *p; + char c; + int linecnt; + size_t linelen; + size_t currentSection_len; + + fp = fopen(fileName, "r"); + if(fp == NULL){ + ShowError("configParse: cannot open '%s' for reading.\n", fileName); + return false; + } + + + // Start with empty section: + currentSection[0] = '\0'; + currentSection_len = 0; + + // + linecnt = 0; + while(1){ + linecnt++; + + if(fgets(line, sizeof(line), fp) != line) + break; + + linelen = strlen(line); + p = line; + + // Skip whitespaces from beginning (space and tab) + _line_begin_skip_whities: + c = *p; + if(c == ' ' || c == '\t'){ + p++; + linelen--; + goto _line_begin_skip_whities; + } + + // Remove linebreaks as (cr or lf) and whitespaces from line end! + _line_end_skip_whities_and_breaks: + c = p[linelen-1]; + if(c == '\r' || c == '\n' || c == ' ' || c == '\t'){ + p[--linelen] = '\0'; + goto _line_end_skip_whities_and_breaks; + } + + // Empty line? + // or line starts with comment (commented out)? + if(linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') + continue; + + // Variable names can contain: + // A-Za-z-_.0-9 + // + // Sections start with [ .. ] (INI Style) + // + c = *p; + + // check what we have.. :) + if(c == '['){ // got section! + // Got Section! + // Search for ] + char *start = (p+1); + + while(1){ + ++p; + c = *p; + + if(c == '\0'){ + ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); + fclose(fp); + return false; + }else if(c == ']'){ // closing backet (section name termination) + if( (p - start + 1) > (sizeof(currentSection) ) ){ + ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); + fclose(fp); + return false; + } + + // Set section! + *p = '\0'; // add termination here. + memcpy(currentSection, start, (p-start)+1 ); // we'll copy \0, too! (we replaced the ] backet with \0.) + currentSection_len = (p-start); + + break; + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // skip .. (allowed char / specifier) + continue; + }else{ + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse section name + + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // Got variable! + // Search for '=' or ':' wich termiantes the name + char *start = p; + char *valuestart = NULL; + size_t start_len; + + while(1){ + ++p; + c = *p; + + if(c == '\0'){ + ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); + fclose(fp); + return false; + }else if( (c == '=') || (c == ':') ){ + // got name termination + + *p = '\0'; // Terminate it so (start) will hold the pointer to the name. + + break; + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // skip .. allowed char + continue; + }else{ + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse var name + + start_len = (p-start); + if(start_len >= VARNAME_LEN){ + ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); + fclose(fp); + return false; + }else if(start_len == 0){ + ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); + fclose(fp); + return false; + } + + + valuestart = (p+1); + + + // Skip whitespace from begin of value (tab and space) + _skip_value_begin_whities: + c = *valuestart; + if(c == ' ' || c == '\t'){ + valuestart++; + goto _skip_value_begin_whities; + } + + // Scan for value termination, + // wich can be \0 or comment start (// or ; (INI) ) + // + p = valuestart; + while(1){ + c = *p; + if(c == '\0'){ + // Terminated by line end. + break; + }else if(c == '/' && p[1] == '/'){ + // terminated by c++ style comment. + *p = '\0'; + break; + }else if(c == ';'){ + // terminated by ini style comment. + *p = '\0'; + break; + } + + p++; + }//endwhile: search var value end. + + + // Strip whitespaces from end of value. + if(valuestart != p){ // not empty! + p--; + _strip_value_end_whities: + c = *p; + if(c == ' ' || c == '\t'){ + *p = '\0'; + p--; + goto _strip_value_end_whities; + } + p++; + } + + + // Buildin Hook: + if( stricmp(start, "import") == 0){ + if( configParse(inst, valuestart) != true){ + ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); + } + }else{ + // put it to db. + struct conf_value *v, *o; + char key[ (SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. + size_t section_len; + + if(*currentSection == '\0'){ // empty / none + strncpy(key, "",9); + section_len = 9; + }else{ + strncpy(key, currentSection, currentSection_len); + section_len = currentSection_len; + } + + key[section_len] = '.'; // Delim + + strncpy(&key[section_len+1], start, start_len); + + key[section_len + start_len + 1] = '\0'; + + + v = makeValue(key, valuestart, (p-valuestart) ); + + // Try to get the old one before + o = strdb_get(inst->db, key); + if(o != NULL){ + strdb_remove(inst->db, key); + aFree(o); // + } + + strdb_put( inst->db, key, v); + } + + + }else{ + ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line) ); + fclose(fp); + return false; + } + + + + } + + + + fclose(fp); + return true; +}//end: configParse() + + +#define MAKEKEY(dest, section, key) { size_t section_len, key_len; \ + if(section == NULL || *section == '\0'){ \ + strncpy(dest, "", 9); \ + section_len = 9; \ + }else{ \ + section_len = strlen(section); \ + strncpy(dest, section, section_len); \ + } \ + \ + dest[section_len] = '.'; \ + \ + key_len = strlen(key); \ + strncpy(&dest[section_len+1], key, key_len); \ + dest[section_len + key_len + 1] = '\0'; \ + } + + +raconf raconf_parse(const char *file_name){ + struct raconf *rc; + + rc = aCalloc(1, sizeof(struct raconf) ); + if(rc == NULL){ + ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); + return NULL; + } + + rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); + // + + if(configParse(rc, file_name) != true){ + ShowError("Failed to Parse Configuration file '%s'\n", file_name); + } + + return rc; +}//end: raconf_parse() + + +void raconf_destroy(raconf rc){ + DBIterator *iter; + struct conf_value *v; + + // Clear all entrys in db. + iter = db_iterator(rc->db); + for( v = (struct conf_value*)dbi_first(iter); dbi_exists(iter); v = (struct conf_value*)dbi_next(iter) ){ + aFree(v); + } + dbi_destroy(iter); + + db_destroy(rc->db); + + aFree(rc); + +}//end: raconf_destroy() + +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->bval; +}//end: raconf_getbool() + + +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return (float)v->floatval; +}//end: raconf_getfloat() + + +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->intval; + +}//end: raconf_getint() + + +const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->strval; +}//end: raconf_getstr() + + +bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->bval; + } + + }else{ + return v->bval; + } +}//end: raconf_getboolEx() + + +float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return (float)v->floatval; + } + + }else{ + return (float)v->floatval; + } + +}//end: raconf_getfloatEx() + + +int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->intval; + } + + }else{ + return v->intval; + } + +}//end: raconf_getintEx() + + +const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->strval; + } + + }else{ + return v->strval; + } + +}//end: raconf_getstrEx() diff --git a/src/common/raconf.h b/src/common/raconf.h new file mode 100644 index 000000000..68a2b51b2 --- /dev/null +++ b/src/common/raconf.h @@ -0,0 +1,59 @@ +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _rA_CONF_H_ +#define _rA_CONF_H_ + +#include "../common/cbasetypes.h" + +// rAthena generic configuration file parser +// +// Config file Syntax is athena style +// extended with ini style support (including sections) +// +// Comments are started with // or ; (ini style) +// + +typedef struct raconf *raconf; + + +/** + * Parses a rAthna Configuration file + * + * @param file_name path to the file to parse + * + * @returns not NULL incase of success + */ +raconf raconf_parse(const char *file_name); + + +/** + * Frees a Handle received from raconf_parse + * + * @param rc - the handle to free + */ +void raconf_destroy(raconf rc); + + +/** + * Gets the value for Section / Key pair, if key not exists returns _default! + * + */ +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); +const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); + +/** + * Gets the value for Section / Key pair, but has fallback section option if not found in section, + * if not found in both - default gets returned. + * + */ +bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default); +float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default); +int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default); +const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); + + + +#endif diff --git a/src/common/thread.c b/src/common/thread.c index 728c6c66a..baf4171da 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -1,3 +1,10 @@ +// +// Basic Threading abstraction (for pthread / win32 based systems) +// +// Author: Florian Wilkemeyer +// +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder #ifdef WIN32 #include "../common/winapi.h" diff --git a/src/common/thread.h b/src/common/thread.h index 8d3441868..a5a66e954 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -1,3 +1,6 @@ +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + #pragma once #ifndef _rA_THREAD_H_ #define _rA_THREAD_H_ -- cgit v1.2.3-70-g09d2 From 3de05fe7cbc2328378e9122a920036feba7a6a7d Mon Sep 17 00:00:00 2001 From: shennetsind Date: Mon, 6 Aug 2012 01:47:50 +0000 Subject: Hello World! with this commit trunk will finally be making use of the gorgeous stuff sirius_black last implemented. we want to make sure everything related to this feature is working as intended so for now its being released under a optional define, after the features stability is confirmed the define will be removed along with the previous processings of the feature. By enabling BETA_THREAD_TEST in /src/config/core.h all your mysql logs, query_sql and query_logsql script functions will be handled by a different thread, therefore any slow queries won't have any effect (e.g. slow down) on the game server. Everyone is welcome on helping us test and debug the features, be aware however I DO NOT RECOMMEND YOU TO ENABLE THIS ON PRODUCTION SERVERS AS OF NOW (which is why while we're all testing it still is a optional feature). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16588 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/thread.c | 2 +- src/config/core.h | 5 + src/map/log.c | 58 +++++++++- src/map/log.h | 7 ++ src/map/map.c | 7 +- src/map/map.h | 17 +++ src/map/script.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/map/script.h | 4 + 8 files changed, 385 insertions(+), 19 deletions(-) (limited to 'src/common/thread.c') diff --git a/src/common/thread.c b/src/common/thread.c index baf4171da..315b310b2 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -271,7 +271,7 @@ int rathread_get_tid(){ #ifdef WIN32 return (int)GetCurrentThreadId(); #else - return (int)pthread_self(); + return (intptr_t)pthread_self(); #endif #endif diff --git a/src/config/core.h b/src/config/core.h index b0e139f27..fba593dc9 100644 --- a/src/config/core.h +++ b/src/config/core.h @@ -31,6 +31,11 @@ /// your map-server using more resources while this is active, comment the line #define SCRIPT_CALLFUNC_CHECK +/// uncomment to enable query_sql script command and mysql logs to function on it's own thread +/// be aware this feature is under tests and you should use at your own risk, we however +/// welcome any feedback you may have regarding this feature, please send us all bug reports. +//#define BETA_THREAD_TEST + //Uncomment to enable the Cell Stack Limit mod. //It's only config is the battle_config cell_stack_limit. //Only chars affected are those defined in BL_CHAR (mobs and players currently) diff --git a/src/map/log.c b/src/map/log.c index de3c850f3..749bd5c28 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -136,8 +136,13 @@ void log_branch(struct map_session_data* sd) if( !log_config.branch ) return; - if( log_config.sql_logs ) - { + if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%s')", log_config.log_branch, sd->status.account_id, sd->status.char_id, sd->status.name, mapindex_id2name(sd->mapindex)); + queryThread_log(entry,e_length); +#else SqlStmt* stmt; stmt = SqlStmt_Malloc(logmysql_handle); if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", log_config.log_branch, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) @@ -149,6 +154,7 @@ void log_branch(struct map_session_data* sd) return; } SqlStmt_Free(stmt); +#endif } else { @@ -179,12 +185,20 @@ void log_pick(int id, int m, e_log_pick_type type, int amount, struct item* itm) if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')", + log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"" ); + queryThread_log(entry,e_length); +#else if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')", log_config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"") ) { Sql_ShowDebug(logmysql_handle); return; } +#endif } else { @@ -226,12 +240,20 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%c', '%d', '%s')", + log_config.log_zeny, sd->status.char_id, src_sd->status.char_id, log_picktype2char(type), amount, mapindex_id2name(sd->mapindex)); + queryThread_log(entry,e_length); +#else if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%c', '%d', '%s')", log_config.log_zeny, sd->status.char_id, src_sd->status.char_id, log_picktype2char(type), amount, mapindex_id2name(sd->mapindex)) ) { Sql_ShowDebug(logmysql_handle); return; } +#endif } else { @@ -259,12 +281,20 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp) if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ", + log_config.log_mvpdrop, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)); + queryThread_log(entry,e_length); +#else if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ", log_config.log_mvpdrop, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)) ) { Sql_ShowDebug(logmysql_handle); return; } +#endif } else { @@ -293,6 +323,12 @@ void log_atcommand(struct map_session_data* sd, const char* message) if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', '%s', '%s', '%s')", log_config.log_gm, sd->status.account_id, sd->status.char_id, sd->status.name ,mapindex_id2name(sd->mapindex), message); + queryThread_log(entry,e_length); +#else SqlStmt* stmt; stmt = SqlStmt_Malloc(logmysql_handle); @@ -306,6 +342,7 @@ void log_atcommand(struct map_session_data* sd, const char* message) return; } SqlStmt_Free(stmt); +#endif } else { @@ -333,6 +370,12 @@ void log_npc(struct map_session_data* sd, const char* message) if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', '%s', '%s', '%s')", log_config.log_npc, sd->status.account_id, sd->status.char_id, sd->status.name, mapindex_id2name(sd->mapindex), message ); + queryThread_log(entry,e_length); +#else SqlStmt* stmt; stmt = SqlStmt_Malloc(logmysql_handle); if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) @@ -345,6 +388,7 @@ void log_npc(struct map_session_data* sd, const char* message) return; } SqlStmt_Free(stmt); +#endif } else { @@ -375,8 +419,13 @@ void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, return; } - if( log_config.sql_logs ) - { + if( log_config.sql_logs ) { +#ifdef BETA_THREAD_TEST + char entry[512]; + int e_length = 0; + e_length = sprintf(entry, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', '%s', '%s')", log_config.log_chat, log_chattype2char(type), type_id, src_charid, src_accid, map, x, y, dst_charname, message ); + queryThread_log(entry,e_length); +#else SqlStmt* stmt; stmt = SqlStmt_Malloc(logmysql_handle); @@ -390,6 +439,7 @@ void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, return; } SqlStmt_Free(stmt); +#endif } else { diff --git a/src/map/log.h b/src/map/log.h index ac85b7ccb..a40a3fcf4 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -79,4 +79,11 @@ extern struct Log_Config } log_config; +#ifdef BETA_THREAD_TEST + struct { + char** entry; + int count; + } logThreadData; +#endif + #endif /* _LOG_H_ */ diff --git a/src/map/map.c b/src/map/map.c index 2239a2f23..30198a32c 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3502,19 +3502,20 @@ int map_sql_close(void) ShowStatus("Close Map DB Connection....\n"); Sql_Free(mmysql_handle); mmysql_handle = NULL; - +#ifndef BETA_THREAD_TEST if (log_config.sql_logs) { ShowStatus("Close Log DB Connection....\n"); Sql_Free(logmysql_handle); logmysql_handle = NULL; } - +#endif return 0; } int log_sql_init(void) { +#ifndef BETA_THREAD_TEST // log db connection logmysql_handle = Sql_Malloc(); @@ -3526,7 +3527,7 @@ int log_sql_init(void) if( strlen(default_codepage) > 0 ) if ( SQL_ERROR == Sql_SetEncoding(logmysql_handle, default_codepage) ) Sql_ShowDebug(logmysql_handle); - +#endif return 0; } diff --git a/src/map/map.h b/src/map/map.h index 6b8ffbe5b..118808713 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -753,6 +753,23 @@ typedef struct elemental_data TBL_ELEM; extern char main_chat_nick[16]; +#ifdef BETA_THREAD_TEST + +extern char default_codepage[32]; +extern int map_server_port; +extern char map_server_ip[32]; +extern char map_server_id[32]; +extern char map_server_pw[32]; +extern char map_server_db[32]; + +extern char log_db_ip[32]; +extern int log_db_port; +extern char log_db_id[32]; +extern char log_db_pw[32]; +extern char log_db_db[32]; + +#endif + #include "../common/sql.h" extern int db_use_sqldbs; diff --git a/src/map/script.c b/src/map/script.c index 4b8afdb24..7b13787ce 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -61,6 +61,13 @@ #include #include +#ifdef BETA_THREAD_TEST + #include "../common/atomic.h" + #include "../common/spinlock.h" + #include "../common/thread.h" + #include "../common/mutex.h" +#endif + /////////////////////////////////////////////////////////////////////////////// //## TODO possible enhancements: [FlavioJS] @@ -306,6 +313,30 @@ extern script_function buildin_func[]; static struct linkdb_node* sleep_db;// int oid -> struct script_state* +#ifdef BETA_THREAD_TEST +/** + * MySQL Query Slave + **/ +static SPIN_LOCK queryThreadLock; +static rAthread queryThread = NULL; +static ramutex queryThreadMutex = NULL; +static racond queryThreadCond = NULL; +static volatile int32 queryThreadTerminate = 0; + +struct queryThreadEntry { + bool ok; + bool type; /* main db or log db? */ + struct script_state *st; +}; + +/* Ladies and Gentleman the Manager! */ +struct { + struct queryThreadEntry **entry;/* array of structs */ + int count; + int timer;/* used to receive processed entries */ +} queryThreadData; +#endif + /*========================================== * ローカルプロトタイプ宣言 (必要な物のみ) *------------------------------------------*/ @@ -3006,6 +3037,7 @@ void script_free_state(struct script_state* st) pop_stack(st, 0, st->stack->sp); aFree(st->stack->stack_data); aFree(st->stack); + st->stack = NULL; st->pos = -1; aFree(st); } @@ -3634,8 +3666,8 @@ static void script_attach_state(struct script_state* st) *------------------------------------------*/ void run_script_main(struct script_state *st) { - int cmdcount=script_config.check_cmdcount; - int gotocount=script_config.check_gotocount; + int cmdcount = script_config.check_cmdcount; + int gotocount = script_config.check_gotocount; TBL_PC *sd; struct script_stack *stack=st->stack; struct npc_data *nd; @@ -3933,8 +3965,175 @@ void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 refcache[0] = key; } } +#ifdef BETA_THREAD_TEST +int buildin_query_sql_sub(struct script_state* st, Sql* handle); + +/* used to receive items the queryThread has already processed */ +int queryThread_timer(int tid, unsigned int tick, int id, intptr_t data) { + int i, cursor = 0; + bool allOk = true; + + EnterSpinLock(&queryThreadLock); + + for( i = 0; i < queryThreadData.count; i++ ) { + struct queryThreadEntry *entry = queryThreadData.entry[i]; + + if( !entry->ok ) { + allOk = false; + continue; + } + + run_script_main(entry->st); + + entry->st = NULL;/* empty entries */ + aFree(entry); + queryThreadData.entry[i] = NULL; + } + + + if( allOk ) { + /* cancel the repeating timer -- it'll re-create itself when necessary, dont need to remain looping */ + delete_timer(queryThreadData.timer, queryThread_timer); + queryThreadData.timer = INVALID_TIMER; + } + + /* now lets clear the mess. */ + for( i = 0; i < queryThreadData.count; i++ ) { + struct queryThreadEntry *entry = queryThreadData.entry[i]; + if( entry == NULL ) + continue;/* entry on hold */ + + /* move */ + memmove(&queryThreadData.entry[cursor], &queryThreadData.entry[i], sizeof(struct queryThreadEntry*)); + + cursor++; + } + + queryThreadData.count = cursor; + + LeaveSpinLock(&queryThreadLock); + + return 0; +} + +void queryThread_add(struct script_state *st, bool type) { + int idx = 0; + struct queryThreadEntry* entry = NULL; + + EnterSpinLock(&queryThreadLock); + + if( queryThreadData.count++ != 0 ) + RECREATE(queryThreadData.entry, struct queryThreadEntry* , queryThreadData.count); + + idx = queryThreadData.count-1; + + CREATE(queryThreadData.entry[idx],struct queryThreadEntry,1); + + entry = queryThreadData.entry[idx]; + + entry->st = st; + entry->ok = false; + entry->type = type; + if( queryThreadData.timer == INVALID_TIMER ) { /* start the receiver timer */ + queryThreadData.timer = add_timer_interval(gettick() + 100, queryThread_timer, 0, 0, 100); + } + + LeaveSpinLock(&queryThreadLock); + + /* unlock the queryThread */ + racond_signal(queryThreadCond); +} +/* adds a new log to the queue */ +void queryThread_log(char * entry, int length) { + int idx = logThreadData.count; + + EnterSpinLock(&queryThreadLock); + + if( logThreadData.count++ != 0 ) + RECREATE(logThreadData.entry, char* , logThreadData.count); + + CREATE(logThreadData.entry[idx], char, length + 1 ); + safestrncpy(logThreadData.entry[idx], entry, length + 1 ); + + LeaveSpinLock(&queryThreadLock); + + /* unlock the queryThread */ + racond_signal(queryThreadCond); +} + +/* queryThread_main */ +static void *queryThread_main(void *x) { + Sql *queryThread_handle = Sql_Malloc(); + int i; + + if ( SQL_ERROR == Sql_Connect(queryThread_handle, map_server_id, map_server_pw, map_server_ip, map_server_port, map_server_db) ) + exit(EXIT_FAILURE); + + if( strlen(default_codepage) > 0 ) + if ( SQL_ERROR == Sql_SetEncoding(queryThread_handle, default_codepage) ) + Sql_ShowDebug(queryThread_handle); + if( log_config.sql_logs ) { + logmysql_handle = Sql_Malloc(); + + if ( SQL_ERROR == Sql_Connect(logmysql_handle, log_db_id, log_db_pw, log_db_ip, log_db_port, log_db_db) ) + exit(EXIT_FAILURE); + + if( strlen(default_codepage) > 0 ) + if ( SQL_ERROR == Sql_SetEncoding(logmysql_handle, default_codepage) ) + Sql_ShowDebug(logmysql_handle); + } + + while( 1 ) { + + if(queryThreadTerminate > 0) + break; + + EnterSpinLock(&queryThreadLock); + + /* mess with queryThreadData within the lock */ + for( i = 0; i < queryThreadData.count; i++ ) { + struct queryThreadEntry *entry = queryThreadData.entry[i]; + + if( entry->ok ) + continue; + else if ( !entry->st || !entry->st->stack ) { + entry->ok = true;/* dispose */ + continue; + } + + buildin_query_sql_sub(entry->st, entry->type ? logmysql_handle : queryThread_handle); + + entry->ok = true;/* we're done with this */ + } + + /* also check for any logs in need to be sent */ + if( log_config.sql_logs ) { + for( i = 0; i < logThreadData.count; i++ ) { + if( SQL_ERROR == Sql_Query(logmysql_handle, logThreadData.entry[i]) ) + Sql_ShowDebug(logmysql_handle); + aFree(logThreadData.entry[i]); + } + logThreadData.count = 0; + } + + LeaveSpinLock(&queryThreadLock); + + ramutex_lock( queryThreadMutex ); + racond_wait( queryThreadCond, queryThreadMutex, -1 ); + ramutex_unlock( queryThreadMutex ); + } + + Sql_Free(queryThread_handle); + + if( log_config.sql_logs ) { + Sql_Free(logmysql_handle); + } + + return NULL; +} +#endif /*========================================== * 終了 *------------------------------------------*/ @@ -4021,25 +4220,88 @@ int do_final_script() { if( atcmd_binding_count != 0 ) aFree(atcmd_binding); +#ifdef BETA_THREAD_TEST + /* QueryThread */ + InterlockedIncrement(&queryThreadTerminate); + racond_signal(queryThreadCond); + rathread_wait(queryThread, NULL); + + // Destroy cond var and mutex. + racond_destroy( queryThreadCond ); + ramutex_destroy( queryThreadMutex ); + + /* Clear missing vars */ + for( i = 0; i < queryThreadData.count; i++ ) { + aFree(queryThreadData.entry[i]); + } + + aFree(queryThreadData.entry); + + for( i = 0; i < logThreadData.count; i++ ) { + aFree(logThreadData.entry[i]); + } + + aFree(logThreadData.entry); +#endif return 0; } /*========================================== * 初期化 *------------------------------------------*/ -int do_init_script() -{ +int do_init_script() { userfunc_db=strdb_alloc(DB_OPT_DUP_KEY,0); scriptlabel_db=strdb_alloc(DB_OPT_DUP_KEY,50); autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0); mapreg_init(); +#ifdef BETA_THREAD_TEST + CREATE(queryThreadData.entry, struct queryThreadEntry*, 1); + queryThreadData.count = 0; + CREATE(logThreadData.entry, char *, 1); + logThreadData.count = 0; + /* QueryThread Start */ + + InitializeSpinLock(&queryThreadLock); + queryThreadData.timer = INVALID_TIMER; + queryThreadTerminate = 0; + queryThreadMutex = ramutex_create(); + queryThreadCond = racond_create(); + + queryThread = rathread_create(queryThread_main, NULL); + + if(queryThread == NULL){ + ShowFatalError("do_init_script: cannot spawn Query Thread.\n"); + exit(EXIT_FAILURE); + } + + add_timer_func_list(queryThread_timer, "queryThread_timer"); +#endif return 0; } int script_reload() { int i; + +#ifdef BETA_THREAD_TEST + /* we're reloading so any queries undergoing should be...exterminated. */ + EnterSpinLock(&queryThreadLock); + + for( i = 0; i < queryThreadData.count; i++ ) { + aFree(queryThreadData.entry[i]); + } + queryThreadData.count = 0; + + if( queryThreadData.timer != INVALID_TIMER ) { + delete_timer(queryThreadData.timer, queryThread_timer); + queryThreadData.timer = INVALID_TIMER; + } + + LeaveSpinLock(&queryThreadLock); +#endif + + userfunc_db->clear(userfunc_db, db_script_free_code_sub); db_clear(scriptlabel_db); @@ -13960,6 +14222,7 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) // Execute the query query = script_getstr(st,2); + if( SQL_ERROR == Sql_QueryStr(handle, query) ) { Sql_ShowDebug(handle); @@ -14014,24 +14277,43 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) // Free data Sql_FreeResult(handle); script_pushint(st, i); + return 0; } -BUILDIN_FUNC(query_sql) -{ +BUILDIN_FUNC(query_sql) { +#ifdef BETA_THREAD_TEST + if( st->state != RERUNLINE ) { + queryThread_add(st,false); + + st->state = RERUNLINE;/* will continue when the query is finished running. */ + } else + st->state = RUN; + + return 0; +#else return buildin_query_sql_sub(st, mmysql_handle); +#endif } -BUILDIN_FUNC(query_logsql) -{ - if( !log_config.sql_logs ) - {// logmysql_handle == NULL +BUILDIN_FUNC(query_logsql) { + if( !log_config.sql_logs ) {// logmysql_handle == NULL ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2)); script_pushint(st,-1); return 1; } - +#ifdef BETA_THREAD_TEST + if( st->state != RERUNLINE ) { + queryThread_add(st,true); + + st->state = RERUNLINE;/* will continue when the query is finished running. */ + } else + st->state = RUN; + + return 0; +#else return buildin_query_sql_sub(st, logmysql_handle); +#endif } //Allows escaping of a given string. diff --git a/src/map/script.h b/src/map/script.h index 41c686660..ed56b8ebe 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -190,4 +190,8 @@ int script_reload(void); // @commands (script based) void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct DBMap **ref); +#ifdef BETA_THREAD_TEST +void queryThread_log(char * entry, int length); +#endif + #endif /* _SCRIPT_H_ */ -- cgit v1.2.3-70-g09d2 From b11bf6e1604097711291265f927e79e8f2af5c54 Mon Sep 17 00:00:00 2001 From: greenboxal2 Date: Sun, 25 Nov 2012 21:20:43 +0000 Subject: Applied AStyle code formating as discussed on tid:74602. Removed /SAFESEH option from MSVC11 projects. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16968 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/char.c | 8159 +++++---- src/char/char.h | 19 +- src/char/int_auction.c | 754 +- src/char/int_elemental.c | 266 +- src/char/int_guild.c | 3072 ++-- src/char/int_guild.h | 26 +- src/char/int_homun.c | 469 +- src/char/int_homun.h | 4 +- src/char/int_mail.c | 721 +- src/char/int_mail.h | 4 +- src/char/int_mercenary.c | 266 +- src/char/int_party.c | 1367 +- src/char/int_party.h | 12 +- src/char/int_pet.c | 505 +- src/char/int_quest.c | 250 +- src/char/int_storage.c | 352 +- src/char/int_storage.h | 2 +- src/char/inter.c | 2022 ++- src/char/inter.h | 4 +- src/common/atomic.h | 139 +- src/common/cbasetypes.h | 147 +- src/common/conf.c | 147 +- src/common/core.c | 447 +- src/common/core.h | 29 +- src/common/db.c | 3246 ++-- src/common/db.h | 1041 +- src/common/des.c | 316 +- src/common/des.h | 12 +- src/common/ers.c | 316 +- src/common/ers.h | 106 +- src/common/evdp.h | 130 +- src/common/evdp_epoll.c | 356 +- src/common/grfio.c | 1205 +- src/common/grfio.h | 14 +- src/common/malloc.c | 1006 +- src/common/malloc.h | 58 +- src/common/mapindex.c | 251 +- src/common/mapindex.h | 10 +- src/common/md5calc.c | 362 +- src/common/md5calc.h | 6 +- src/common/mempool.c | 899 +- src/common/mempool.h | 62 +- src/common/mmo.h | 929 +- src/common/mutex.c | 256 +- src/common/mutex.h | 50 +- src/common/netbuffer.c | 349 +- src/common/netbuffer.h | 78 +- src/common/network.c | 1809 +- src/common/network.h | 220 +- src/common/nullpo.c | 96 +- src/common/nullpo.h | 30 +- src/common/raconf.c | 1037 +- src/common/raconf.h | 34 +- src/common/random.c | 36 +- src/common/showmsg.c | 1351 +- src/common/showmsg.h | 104 +- src/common/socket.c | 1983 +- src/common/socket.h | 75 +- src/common/spinlock.h | 108 +- src/common/sql.c | 1216 +- src/common/sql.h | 139 +- src/common/strlib.c | 1729 +- src/common/strlib.h | 119 +- src/common/thread.c | 384 +- src/common/thread.h | 62 +- src/common/timer.c | 479 +- src/common/timer.h | 32 +- src/common/utils.c | 403 +- src/common/utils.h | 8 +- src/common/winapi.h | 6 +- src/config/const.h | 74 +- src/login/account.h | 227 +- src/login/account_sql.c | 1123 +- src/login/ipban.h | 2 +- src/login/ipban_sql.c | 340 +- src/login/login.c | 3198 ++-- src/login/login.h | 123 +- src/login/loginlog.h | 4 +- src/login/loginlog_sql.c | 241 +- src/map/atcommand.c | 14212 ++++++++------- src/map/atcommand.h | 28 +- src/map/battle.c | 11244 ++++++------ src/map/battle.h | 849 +- src/map/battleground.c | 329 +- src/map/battleground.h | 26 +- src/map/buyingstore.c | 804 +- src/map/buyingstore.h | 32 +- src/map/chat.c | 570 +- src/map/chat.h | 50 +- src/map/chrif.c | 2531 +-- src/map/chrif.h | 38 +- src/map/clif.c | 21218 +++++++++++----------- src/map/clif.h | 842 +- src/map/date.c | 66 +- src/map/duel.c | 248 +- src/map/duel.h | 20 +- src/map/elemental.c | 1458 +- src/map/elemental.h | 56 +- src/map/guild.c | 2853 ++- src/map/guild.h | 26 +- src/map/homunculus.c | 2062 +-- src/map/homunculus.h | 110 +- src/map/instance.c | 631 +- src/map/instance.h | 32 +- src/map/intif.c | 3021 +-- src/map/intif.h | 20 +- src/map/itemdb.c | 2238 ++- src/map/itemdb.h | 226 +- src/map/log.c | 878 +- src/map/log.h | 107 +- src/map/mail.c | 226 +- src/map/mail.h | 2 +- src/map/map.c | 5622 +++--- src/map/map.h | 967 +- src/map/mapreg.h | 6 +- src/map/mapreg_sql.c | 311 +- src/map/mercenary.c | 640 +- src/map/mercenary.h | 58 +- src/map/mob.c | 7791 ++++---- src/map/mob.h | 359 +- src/map/npc.c | 6196 +++---- src/map/npc.h | 219 +- src/map/npc_chat.c | 568 +- src/map/party.c | 1823 +- src/map/party.h | 52 +- src/map/path.c | 686 +- src/map/path.h | 10 +- src/map/pc.c | 16188 +++++++++-------- src/map/pc.h | 1176 +- src/map/pc_groups.c | 657 +- src/map/pc_groups.h | 92 +- src/map/pet.c | 2286 ++- src/map/pet.h | 140 +- src/map/quest.c | 516 +- src/map/quest.h | 26 +- src/map/script.c | 26239 +++++++++++++------------- src/map/script.h | 238 +- src/map/searchstore.c | 593 +- src/map/searchstore.h | 77 +- src/map/skill.c | 34344 ++++++++++++++++++----------------- src/map/skill.h | 3268 ++-- src/map/status.c | 20714 +++++++++++---------- src/map/status.h | 3126 ++-- src/map/storage.c | 922 +- src/map/storage.h | 4 +- src/map/trade.c | 1014 +- src/map/trade.h | 4 +- src/map/unit.c | 4228 +++-- src/map/unit.h | 104 +- src/map/vending.c | 654 +- src/map/vending.h | 24 +- src/test/test_spinlock.c | 160 +- src/tool/mapcache.c | 484 +- vcproj-12/char-server_sql.vcxproj | 2 + vcproj-12/login-server_sql.vcxproj | 2 + vcproj-12/map-server_sql.vcxproj | 2 + vcproj-12/mapcache.vcxproj | 4 +- vcproj-12/mapcache.vcxproj.filters | 1 + 158 files changed, 128222 insertions(+), 128461 deletions(-) (limited to 'src/common/thread.c') diff --git a/src/char/char.c b/src/char/char.c index 234a91b79..0db64bf07 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -30,9 +30,9 @@ #include // private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" -#define SQL_CONF_NAME "conf/inter_athena.conf" +#define CHAR_CONF_NAME "conf/char_athena.conf" +#define LAN_CONF_NAME "conf/subnet_athena.conf" +#define SQL_CONF_NAME "conf/inter_athena.conf" char char_db[256] = "char"; char scdata_db[256] = "sc_data"; @@ -68,18 +68,18 @@ char ragsrvinfo_db[256] = "ragsrvinfo"; // show loading/saving messages int save_log = 1; -static DBMap* char_db_; // int char_id -> struct mmo_charstatus* +static DBMap *char_db_; // int char_id -> struct mmo_charstatus* char db_path[1024] = "db"; int db_use_sqldbs; struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; + int fd; + uint32 ip; + uint16 port; + int users; + unsigned short map[MAX_MAP_PER_SERVER]; } server[MAX_MAP_SERVERS]; int login_fd=-1, char_fd=-1; @@ -109,28 +109,28 @@ int char_per_account = 0; //Maximum chars per account (default unlimited) [Siriu int char_del_level = 0; //From which level u can delete character [Lupus] int char_del_delay = 86400; -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] +int log_char = 1; // loggin char or not [devil] +int log_inter = 1; // loggin inter or not [devil] // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; struct char_session_data { - bool auth; // whether the session is authed or not - int account_id, login_id1, login_id2, sex; - int found_char[MAX_CHARS]; // ids of chars on this account - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; // permission - uint32 version; - uint8 clienttype; - char new_name[NAME_LENGTH]; - char birthdate[10+1]; // YYYY-MM-DD + bool auth; // whether the session is authed or not + int account_id, login_id1, login_id2, sex; + int found_char[MAX_CHARS]; // ids of chars on this account + char email[40]; // e-mail (default: a@a.com) by [Yor] + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; // permission + uint32 version; + uint8 clienttype; + char new_name[NAME_LENGTH]; + char birthdate[10+1]; // YYYY-MM-DD }; int max_connect_user = 0; @@ -167,32 +167,32 @@ int console = 0; #define AUTH_TIMEOUT 30000 struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; - unsigned changing_mapservers : 1; + int account_id; + int char_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + int sex; + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; + unsigned changing_mapservers : 1; }; -static DBMap* auth_db; // int account_id -> struct auth_node* +static DBMap *auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- // Online User Database //----------------------------------------------------- struct online_char_data { - int account_id; - int char_id; - int fd; - int waiting_disconnect; - short server; // -2: unknown server, -1: not connected, 0+: id of server + int account_id; + int char_id; + int fd; + int waiting_disconnect; + short server; // -2: unknown server, -1: not connected, 0+: id of server }; -static DBMap* online_char_db; // int account_id -> struct online_char_data* +static DBMap *online_char_db; // int account_id -> struct online_char_data* static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); int delete_char_sql(int char_id); @@ -201,137 +201,129 @@ int delete_char_sql(int char_id); */ static DBData create_online_char_data(DBKey key, va_list args) { - struct online_char_data* character; - CREATE(character, struct online_char_data, 1); - character->account_id = key.i; - character->char_id = -1; - character->server = -1; - character->fd = -1; - character->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(character); + struct online_char_data *character; + CREATE(character, struct online_char_data, 1); + character->account_id = key.i; + character->char_id = -1; + character->server = -1; + character->fd = -1; + character->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(character); } void set_char_charselect(int account_id) { - struct online_char_data* character; + struct online_char_data *character; - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); + character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; + if (character->server > -1) + if (server[character->server].users > 0) // Prevent this value from going negative. + server[character->server].users--; - character->char_id = -1; - character->server = -1; + character->char_id = -1; + character->server = -1; - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + if (login_fd > 0 && !session[login_fd]->flag.eof) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_online(int map_id, int char_id, int account_id) { - struct online_char_data* character; - struct mmo_charstatus *cp; - - //Update DB - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Check to see for online conflicts - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if( character->char_id != -1 && character->server > -1 && character->server != map_id ) - { - ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, map_id, account_id, char_id); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - - //Update state data - character->char_id = char_id; - character->server = map_id; - - if( character->server > -1 ) - server[character->server].users++; - - //Get rid of disconnect timer - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. - cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); - - //Notify login server - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data *character; + struct mmo_charstatus *cp; + + //Update DB + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + //Check to see for online conflicts + character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); + if (character->char_id != -1 && character->server > -1 && character->server != map_id) { + ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, map_id, account_id, char_id); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + + //Update state data + character->char_id = char_id; + character->server = map_id; + + if (character->server > -1) + server[character->server].users++; + + //Get rid of disconnect timer + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. + cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); + inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); + + //Notify login server + if (login_fd > 0 && !session[login_fd]->flag.eof) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_offline(int char_id, int account_id) { - struct online_char_data* character; - - if ( char_id == -1 ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) - Sql_ShowDebug(sql_handle); - } - else - { - struct mmo_charstatus* cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); - if (cp) - idb_remove(char_db_,char_id); - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - } - - if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) - { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; - - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - if(character->char_id == char_id) - { - character->char_id = -1; - character->server = -1; - } - - //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? - } - - //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. - if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data *character; + + if (char_id == -1) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id)) + Sql_ShowDebug(sql_handle); + } else { + struct mmo_charstatus *cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); + inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); + if (cp) + idb_remove(char_db_,char_id); + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) + Sql_ShowDebug(sql_handle); + } + + if ((character = (struct online_char_data *)idb_get(online_char_db, account_id)) != NULL) { + //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] + if (character->server > -1) + if (server[character->server].users > 0) // Prevent this value from going negative. + server[character->server].users--; + + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + if (character->char_id == char_id) { + character->char_id = -1; + character->server = -1; + } + + //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? + } + + //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. + if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272c; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } /** @@ -339,18 +331,18 @@ void set_char_offline(int char_id, int account_id) */ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; + struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); + int server = va_arg(ap, int); + if (server == -1) { + character->char_id = -1; + character->server = -1; + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + } else if (character->server == server) + character->server = -2; //In some map server that we aren't connected to. + return 0; } /** @@ -358,48 +350,48 @@ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int char_db_kickoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); - int server_id = va_arg(ap, int); + struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); + int server_id = va_arg(ap, int); - if (server_id > -1 && character->server != server_id) - return 0; + if (server_id > -1 && character->server != server_id) + return 0; - //Kick out any connected characters, and set them offline as appropriate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == INVALID_TIMER) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail + //Kick out any connected characters, and set them offline as appropriate. + if (character->server > -1) + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); + else if (character->waiting_disconnect == INVALID_TIMER) + set_char_offline(character->char_id, character->account_id); + else + return 0; // fail - return 1; + return 1; } void set_all_offline(int id) { - if (id < 0) - ShowNotice("Sending all users offline.\n"); - else - ShowNotice("Sending users of map-server %d offline.\n",id); - online_char_db->foreach(online_char_db,char_db_kickoffline,id); - - if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) - return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); + if (id < 0) + ShowNotice("Sending all users offline.\n"); + else + ShowNotice("Sending users of map-server %d offline.\n",id); + online_char_db->foreach(online_char_db,char_db_kickoffline,id); + + if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) + return; + //Tell login-server to also mark all our characters as offline. + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2737; + WFIFOSET(login_fd,2); } void set_all_offline_sql(void) { - //Set all players to 'OFFLINE' - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); + //Set all players to 'OFFLINE' + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db)) + Sql_ShowDebug(sql_handle); } /** @@ -407,949 +399,920 @@ void set_all_offline_sql(void) */ static DBData create_charstatus(DBKey key, va_list args) { - struct mmo_charstatus *cp; - cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); - cp->char_id = key.i; - return db_ptr2data(cp); + struct mmo_charstatus *cp; + cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); + cp->char_id = key.i; + return db_ptr2data(cp); } int inventory_to_sql(const struct item items[], int max, int id); -int mmo_char_tosql(int char_id, struct mmo_charstatus* p) +int mmo_char_tosql(int char_id, struct mmo_charstatus *p) { - int i = 0; - int count = 0; - int diff = 0; - char save_status[128]; //For displaying save information. [Skotlex] - struct mmo_charstatus *cp; - int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. - StringBuf buf; - - if (char_id!=p->char_id) return 0; - - cp = idb_ensure(char_db_, char_id, create_charstatus); - - StringBuf_Init(&buf); - memset(save_status, 0, sizeof(save_status)); - - //map inventory data - if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) { - if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) - strcat(save_status, " inventory"); - else - errors++; - } - - //map cart data - if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) { - if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) - strcat(save_status, " cart"); - else - errors++; - } - - //map storage data - if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) { - if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) - strcat(save_status, " storage"); - else - errors++; - } - - if ( - (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || - (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || - (p->zeny != cp->zeny) || - (p->last_point.map != cp->last_point.map) || - (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || - (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || - (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || - (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || - (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || - (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || - (p->option != cp->option) || - (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || - (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || - (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || - (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || - (p->rename != cp->rename) || (p->robe != cp->robe) - ) - { //Save status - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," - "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," - "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," - "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," - "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," - "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu',`robe`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, - mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, - (unsigned long)p->delete_date, // FIXME: platform-dependent size - p->robe, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status"); - } - - //Values that will seldom change (to speed up saving) - if ( - (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || - (p->class_ != cp->class_) || - (p->partner_id != cp->partner_id) || (p->father != cp->father) || - (p->mother != cp->mother) || (p->child != cp->child) || - (p->karma != cp->karma) || (p->manner != cp->manner) || - (p->fame != cp->fame) - ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," - "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," - "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," - "`karma`='%d',`manner`='%d', `fame`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->class_, - p->hair, p->hair_color, p->clothes_color, - p->partner_id, p->father, p->mother, p->child, - p->karma, p->manner, p->fame, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status2"); - } - - /* Mercenary Owner */ - if( (p->mer_id != cp->mer_id) || - (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || - (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || - (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) ) - { - if (mercenary_owner_tosql(char_id, p)) - strcat(save_status, " mercenary"); - else - errors++; - } - - //memo points - if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) - { - char esc_mapname[NAME_LENGTH*2+1]; - - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - //insert here. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); - for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) - { - if( p->memo_point[i].map ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); - StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " memo"); - } - - //FIXME: is this neccessary? [ultramage] - for(i=0;iskill[i].lv != 0) && (p->skill[i].id == 0)) - p->skill[i].id = i; // Fix skill tree - - - //skills - if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) - { - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); - //insert here. - for( i = 0, count = 0; i < MAX_SKILL; ++i ) - { - if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) - { - if( p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0 ) - continue; - if( p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) - continue; - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - strcat(save_status, " skills"); - } - - diff = 0; - for(i = 0; i < MAX_FRIENDS; i++){ - if(p->friends[i].char_id != cp->friends[i].char_id || - p->friends[i].account_id != cp->friends[i].account_id){ - diff = 1; - break; - } - } - - if(diff == 1) - { //Save friends - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); - for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) - { - if( p->friends[i].char_id > 0 ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); - count++; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " friends"); - } + int i = 0; + int count = 0; + int diff = 0; + char save_status[128]; //For displaying save information. [Skotlex] + struct mmo_charstatus *cp; + int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. + StringBuf buf; + + if (char_id!=p->char_id) return 0; + + cp = idb_ensure(char_db_, char_id, create_charstatus); + + StringBuf_Init(&buf); + memset(save_status, 0, sizeof(save_status)); + + //map inventory data + if (memcmp(p->inventory, cp->inventory, sizeof(p->inventory))) { + if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) + strcat(save_status, " inventory"); + else + errors++; + } + + //map cart data + if (memcmp(p->cart, cp->cart, sizeof(p->cart))) { + if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) + strcat(save_status, " cart"); + else + errors++; + } + + //map storage data + if (memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items))) { + if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) + strcat(save_status, " storage"); + else + errors++; + } + + if ( + (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || + (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || + (p->zeny != cp->zeny) || + (p->last_point.map != cp->last_point.map) || + (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || + (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || + (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || + (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || + (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || + (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || + (p->option != cp->option) || + (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || + (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || + (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || + (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || + (p->rename != cp->rename) || (p->robe != cp->robe) + ) { + //Save status + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," + "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," + "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," + "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," + "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," + "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," + "`delete_date`='%lu',`robe`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->base_level, p->job_level, + p->base_exp, p->job_exp, p->zeny, + p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk, + p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, + mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, + (unsigned long)p->delete_date, // FIXME: platform-dependent size + p->robe, + p->account_id, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status"); + } + + //Values that will seldom change (to speed up saving) + if ( + (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || + (p->class_ != cp->class_) || + (p->partner_id != cp->partner_id) || (p->father != cp->father) || + (p->mother != cp->mother) || (p->child != cp->child) || + (p->karma != cp->karma) || (p->manner != cp->manner) || + (p->fame != cp->fame) + ) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," + "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," + "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," + "`karma`='%d',`manner`='%d', `fame`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->class_, + p->hair, p->hair_color, p->clothes_color, + p->partner_id, p->father, p->mother, p->child, + p->karma, p->manner, p->fame, + p->account_id, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status2"); + } + + /* Mercenary Owner */ + if ((p->mer_id != cp->mer_id) || + (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || + (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || + (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith)) { + if (mercenary_owner_tosql(char_id, p)) + strcat(save_status, " mercenary"); + else + errors++; + } + + //memo points + if (memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point))) { + char esc_mapname[NAME_LENGTH*2+1]; + + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + //insert here. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); + for (i = 0, count = 0; i < MAX_MEMOPOINTS; ++i) { + if (p->memo_point[i].map) { + if (count) + StringBuf_AppendStr(&buf, ","); + Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); + StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); + ++count; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " memo"); + } + + //FIXME: is this neccessary? [ultramage] + for (i=0; iskill[i].lv != 0) && (p->skill[i].id == 0)) + p->skill[i].id = i; // Fix skill tree + + + //skills + if (memcmp(p->skill, cp->skill, sizeof(p->skill))) { + //`skill` (`char_id`, `id`, `lv`) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); + //insert here. + for (i = 0, count = 0; i < MAX_SKILL; ++i) { + if (p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY) { + if (p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0) + continue; + if (p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0) + continue; + if (count) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); + ++count; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + strcat(save_status, " skills"); + } + + diff = 0; + for (i = 0; i < MAX_FRIENDS; i++) { + if (p->friends[i].char_id != cp->friends[i].char_id || + p->friends[i].account_id != cp->friends[i].account_id) { + diff = 1; + break; + } + } + + if (diff == 1) { + //Save friends + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); + for (i = 0, count = 0; i < MAX_FRIENDS; ++i) { + if (p->friends[i].char_id > 0) { + if (count) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); + count++; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " friends"); + } #ifdef HOTKEY_SAVING - // hotkeys - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); - diff = 0; - for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ - if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) - { - if( diff ) - StringBuf_AppendStr(&buf, ",");// not the first hotkey - StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); - diff = 1; - } - } - if(diff) { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " hotkeys"); - } + // hotkeys + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); + diff = 0; + for (i = 0; i < ARRAYLENGTH(p->hotkeys); i++) { + if (memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) { + if (diff) + StringBuf_AppendStr(&buf, ",");// not the first hotkey + StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); + diff = 1; + } + } + if (diff) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " hotkeys"); + } #endif - StringBuf_Destroy(&buf); - if (save_status[0]!='\0' && save_log) - ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); - if (!errors) - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 0; + StringBuf_Destroy(&buf); + if (save_status[0]!='\0' && save_log) + ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); + if (!errors) + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 0; } /// Saves an array of 'item' entries into the specified table. int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) { - StringBuf buf; - SqlStmt* stmt; - int i; - int j; - const char* tablename; - const char* selectoption; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - switch (tableswitch) { - case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; - case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; - case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; - case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; - default: - ShowError("Invalid table name!\n"); - return 1; - } - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCalloc(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - if( j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time ) - ; //Do nothing. - else - { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", - tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) - {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; + StringBuf buf; + SqlStmt *stmt; + int i; + int j; + const char *tablename; + const char *selectoption; + struct item item; // temp storage variable + bool *flag; // bit array for inventory matching + bool found; + int errors = 0; + + switch (tableswitch) { + case TABLE_INVENTORY: + tablename = inventory_db; + selectoption = "char_id"; + break; + case TABLE_CART: + tablename = cart_db; + selectoption = "char_id"; + break; + case TABLE_STORAGE: + tablename = storage_db; + selectoption = "account_id"; + break; + case TABLE_GUILD_STORAGE: + tablename = guild_storage_db; + selectoption = "guild_id"; + break; + default: + ShowError("Invalid table name!\n"); + return 1; + } + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + for (j = 0; j < MAX_SLOTS; ++j) + SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool *) aCalloc(max, sizeof(bool)); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + found = false; + // search for the presence of the item in the char's inventory + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); + if (j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time) + ; //Do nothing. + else { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", + tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if (!found) { + // Item not present in inventory, remove it. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (found) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } /* pretty much a copy of memitemdata_to_sql except it handles inventory_db exclusively, * - this is required because inventory db is the only one with the 'favorite' column. */ -int inventory_to_sql(const struct item items[], int max, int id) { - StringBuf buf; - SqlStmt* stmt; - int i; - int j; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCalloc(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - if( j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time && - items[i].favorite == item.favorite ) - ; //Do nothing. - else { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", - inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; +int inventory_to_sql(const struct item items[], int max, int id) +{ + StringBuf buf; + SqlStmt *stmt; + int i; + int j; + struct item item; // temp storage variable + bool *flag; // bit array for inventory matching + bool found; + int errors = 0; + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); + for (j = 0; j < MAX_SLOTS; ++j) + SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool *) aCalloc(max, sizeof(bool)); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + found = false; + // search for the presence of the item in the char's inventory + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); + if (j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time && + items[i].favorite == item.favorite) + ; //Do nothing. + else { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", + inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if (!found) { // Item not present in inventory, remove it. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (found) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } -int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p); +int mmo_char_tobuf(uint8 *buf, struct mmo_charstatus *p); //===================================================================================================== // Loads the basic character rooster for the given account. Returns total buffer used. -int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) +int mmo_chars_fromsql(struct char_session_data *sd, uint8 *buf) { - SqlStmt* stmt; - struct mmo_charstatus p; - int j = 0, i; - char last_map[MAP_NAME_LENGTH_EXT]; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - memset(&p, 0, sizeof(p)); - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`" - " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) - { - p.last_point.map = mapindex_name2id(last_map); - sd->found_char[i] = p.char_id; - j += mmo_char_tobuf(WBUFP(buf, j), &p); - } - for( ; i < MAX_CHARS; i++ ) - sd->found_char[i] = -1; - - memset(sd->new_name,0,sizeof(sd->new_name)); - - SqlStmt_Free(stmt); - return j; + SqlStmt *stmt; + struct mmo_charstatus p; + int j = 0, i; + char last_map[MAP_NAME_LENGTH_EXT]; + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + memset(&p, 0, sizeof(p)); + + // read char data + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," + "`robe`" + " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) + ) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++) { + p.last_point.map = mapindex_name2id(last_map); + sd->found_char[i] = p.char_id; + j += mmo_char_tobuf(WBUFP(buf, j), &p); + } + for (; i < MAX_CHARS; i++) + sd->found_char[i] = -1; + + memset(sd->new_name,0,sizeof(sd->new_name)); + + SqlStmt_Free(stmt); + return j; } //===================================================================================================== -int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything) +int mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool load_everything) { - int i,j; - char t_msg[128] = ""; - struct mmo_charstatus* cp; - StringBuf buf; - SqlStmt* stmt; - char last_map[MAP_NAME_LENGTH_EXT]; - char save_map[MAP_NAME_LENGTH_EXT]; - char point_map[MAP_NAME_LENGTH_EXT]; - struct point tmp_point; - struct item tmp_item; - struct s_skill tmp_skill; - struct s_friend tmp_friend; + int i,j; + char t_msg[128] = ""; + struct mmo_charstatus *cp; + StringBuf buf; + SqlStmt *stmt; + char last_map[MAP_NAME_LENGTH_EXT]; + char save_map[MAP_NAME_LENGTH_EXT]; + char point_map[MAP_NAME_LENGTH_EXT]; + struct point tmp_point; + struct item tmp_item; + struct s_skill tmp_skill; + struct s_friend tmp_friend; #ifdef HOTKEY_SAVING - struct hotkey tmp_hotkey; - int hotkey_num; + struct hotkey tmp_hotkey; + int hotkey_num; #endif - memset(p, 0, sizeof(struct mmo_charstatus)); - - if (save_log) ShowInfo("Char load request (%d)\n", char_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," - "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" - " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - if( SQL_ERROR == SqlStmt_NextRow(stmt) ) - { - ShowError("Requested non-existant character id: %d!\n", char_id); - SqlStmt_Free(stmt); - return 0; - } - p->last_point.map = mapindex_name2id(last_map); - p->save_point.map = mapindex_name2id(save_map); - - strcat(t_msg, " status"); - - if (!load_everything) // For quick selection of data when displaying the char menu - { - SqlStmt_Free(stmt); - return 1; - } - - //read memo data - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - tmp_point.map = mapindex_name2id(point_map); - memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); - } - strcat(t_msg, " memo"); - - //read inventory - //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for( i = 0; i < MAX_SLOTS; ++i ) - StringBuf_Printf(&buf, ", `card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); - - strcat(t_msg, " inventory"); - - //read cart - //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Clear(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); - strcat(t_msg, " cart"); - - //read storage - storage_fromsql(p->account_id, &p->storage); - strcat(t_msg, " storage"); - - //read skill - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - tmp_skill.flag = SKILL_FLAG_PERMANENT; - - for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - if( tmp_skill.id < ARRAYLENGTH(p->skill) ) - memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " skills"); - - //read friends - //`friends` (`char_id`, `friend_account`, `friend_id`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); - strcat(t_msg, " friends"); + memset(p, 0, sizeof(struct mmo_charstatus)); + + if (save_log) ShowInfo("Char load request (%d)\n", char_id); + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + + // read char data + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," + "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" + " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) + ) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + if (SQL_ERROR == SqlStmt_NextRow(stmt)) { + ShowError("Requested non-existant character id: %d!\n", char_id); + SqlStmt_Free(stmt); + return 0; + } + p->last_point.map = mapindex_name2id(last_map); + p->save_point.map = mapindex_name2id(save_map); + + strcat(t_msg, " status"); + + if (!load_everything) { // For quick selection of data when displaying the char menu + SqlStmt_Free(stmt); + return 1; + } + + //read memo data + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { + tmp_point.map = mapindex_name2id(point_map); + memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); + } + strcat(t_msg, " memo"); + + //read inventory + //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for (i = 0; i < MAX_SLOTS; ++i) + StringBuf_Printf(&buf, ", `card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); + + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_SLOTS; ++i) + if (SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); + + strcat(t_msg, " inventory"); + + //read cart + //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Clear(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); + + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_SLOTS; ++i) + if (SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); + strcat(t_msg, " cart"); + + //read storage + storage_fromsql(p->account_id, &p->storage); + strcat(t_msg, " storage"); + + //read skill + //`skill` (`char_id`, `id`, `lv`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + tmp_skill.flag = SKILL_FLAG_PERMANENT; + + for (i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { + if (tmp_skill.id < ARRAYLENGTH(p->skill)) + memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " skills"); + + //read friends + //`friends` (`char_id`, `friend_account`, `friend_id`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); + strcat(t_msg, " friends"); #ifdef HOTKEY_SAVING - //read hotkeys - //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS ) - memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " hotkeys"); + //read hotkeys + //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + if (hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS) + memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " hotkeys"); #endif - /* Mercenary Owner DataBase */ - mercenary_owner_fromsql(char_id, p); - strcat(t_msg, " mercenary"); + /* Mercenary Owner DataBase */ + mercenary_owner_fromsql(char_id, p); + strcat(t_msg, " mercenary"); - if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); - cp = idb_ensure(char_db_, char_id, create_charstatus); - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 1; + cp = idb_ensure(char_db_, char_id, create_charstatus); + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 1; } //========================================================================================================== int mmo_char_sql_init(void) { - char_db_= idb_alloc(DB_OPT_RELEASE_DATA); + char_db_= idb_alloc(DB_OPT_RELEASE_DATA); - ShowStatus("Characters per Account: '%d'.\n", char_per_account); + ShowStatus("Characters per Account: '%d'.\n", char_per_account); - //the 'set offline' part is now in check_login_conn ... - //if the server connects to loginserver - //it will dc all off players - //and send the loginserver the new state.... + //the 'set offline' part is now in check_login_conn ... + //if the server connects to loginserver + //it will dc all off players + //and send the loginserver the new state.... - // Force all users offline in sql when starting char-server - // (useful when servers crashs and don't clean the database) - set_all_offline_sql(); + // Force all users offline in sql when starting char-server + // (useful when servers crashs and don't clean the database) + set_all_offline_sql(); - return 0; + return 0; } //----------------------------------- @@ -1357,199 +1320,195 @@ int mmo_char_sql_init(void) //----------------------------------- int rename_char_sql(struct char_session_data *sd, int char_id) { - struct mmo_charstatus char_dat; - char esc_name[NAME_LENGTH*2+1]; - - if( sd->new_name[0] == 0 ) // Not ready for rename - return 2; - - if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. - return 2; - - if( char_dat.rename == 0 ) - return 1; - - Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); - - // check if the char exist - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return 4; - } - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 3; - } - - // Change character's name into guild_db. - if( char_dat.guild_id ) - inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); - - safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); - memset(sd->new_name,0,sizeof(sd->new_name)); - - // log change - if( log_char ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", - charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - return 0; + struct mmo_charstatus char_dat; + char esc_name[NAME_LENGTH*2+1]; + + if (sd->new_name[0] == 0) // Not ready for rename + return 2; + + if (!mmo_char_fromsql(char_id, &char_dat, false)) // Only the short data is needed. + return 2; + + if (char_dat.rename == 0) + return 1; + + Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); + + // check if the char exist + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return 4; + } + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id)) { + Sql_ShowDebug(sql_handle); + return 3; + } + + // Change character's name into guild_db. + if (char_dat.guild_id) + inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); + + safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); + memset(sd->new_name,0,sizeof(sd->new_name)); + + // log change + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", + charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name)) + Sql_ShowDebug(sql_handle); + } + + return 0; } -int check_char_name(char * name, char * esc_name) +int check_char_name(char *name, char *esc_name) { - int i; - - // check length of character name - if( name[0] == '\0' ) - return -2; // empty character name - /** - * The client does not allow you to create names with less than 4 characters, however, - * the use of WPE can bypass this, and this fixes the exploit. - **/ - if( strlen( name ) < 4 ) - return -2; - // check content of character name - if( remove_control_chars(name) ) - return -2; // control chars in name - - // check for reserved names - if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) - return -1; // nick reserved for internal server messages - - // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) - { // only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return -2; - } - else if( char_name_option == 2 ) - { // letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return -2; - } - if( name_ignoring_case ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } else { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } - if( Sql_NumRows(sql_handle) > 0 ) - return -1; // name already exists - - return 0; + int i; + + // check length of character name + if (name[0] == '\0') + return -2; // empty character name + /** + * The client does not allow you to create names with less than 4 characters, however, + * the use of WPE can bypass this, and this fixes the exploit. + **/ + if (strlen(name) < 4) + return -2; + // check content of character name + if (remove_control_chars(name)) + return -2; // control chars in name + + // check for reserved names + if (strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0) + return -1; // nick reserved for internal server messages + + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { + // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) + return -2; + } else if (char_name_option == 2) { + // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) + return -2; + } + if (name_ignoring_case) { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -2; + } + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -2; + } + } + if (Sql_NumRows(sql_handle) > 0) + return -1; // name already exists + + return 0; } //----------------------------------- // Function to create a new character //----------------------------------- #if PACKETVER >= 20120307 -int make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style) { - int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; +int make_new_char_sql(struct char_session_data *sd, char *name_, int slot, int hair_color, int hair_style) +{ + int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; #else -int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) { +int make_new_char_sql(struct char_session_data *sd, char *name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +{ #endif - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - int char_id, flag; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + int char_id, flag; - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - flag = check_char_name(name,esc_name); - if( flag < 0 ) - return flag; + flag = check_char_name(name,esc_name); + if (flag < 0) + return flag; - //check other inputs + //check other inputs #if PACKETVER >= 20120307 - if(slot >= MAX_CHARS) + if (slot >= MAX_CHARS) #else - if((slot >= MAX_CHARS) // slots - || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats - || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values - || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs + if ((slot >= MAX_CHARS) // slots + || (str + agi + vit + int_ + dex + luk != 6*5) // stats + || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values + || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10)) // pairs #endif - return -2; // invalid input - - if (hair_style > 17 || hair_color > 8) - return -2; - - // check the number of already existing chars in this account - if( char_per_account != 0 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) >= char_per_account ) - return -2; // character account limit exceeded - } - - // check char slot - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) > 0 ) - return -2; // slot already in use - - // validation success, log result - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) - Sql_ShowDebug(sql_handle); - } + return -2; // invalid input + + if (hair_style > 17 || hair_color > 8) + return -2; + + // check the number of already existing chars in this account + if (char_per_account != 0) { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id)) + Sql_ShowDebug(sql_handle); + if (Sql_NumRows(sql_handle) >= char_per_account) + return -2; // character account limit exceeded + } + + // check char slot + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot)) + Sql_ShowDebug(sql_handle); + if (Sql_NumRows(sql_handle) > 0) + return -2; // slot already in use + + // validation success, log result + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color)) + Sql_ShowDebug(sql_handle); + } #if PACKETVER >= 20120307 - //Insert the new char entry to the database - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) - { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #else - //Insert the new char entry to the database - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) - { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #endif - //Retrieve the newly auto-generated char id - char_id = (int)Sql_LastInsertId(sql_handle); - //Give the char the default items - if (start_weapon > 0) { //add Start Weapon (Knife?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - if (start_armor > 0) { //Add default armor (cotton shirt?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); - return char_id; + //Retrieve the newly auto-generated char id + char_id = (int)Sql_LastInsertId(sql_handle); + //Give the char the default items + if (start_weapon > 0) { //add Start Weapon (Knife?) + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1)) + Sql_ShowDebug(sql_handle); + } + if (start_armor > 0) { //Add default armor (cotton shirt?) + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1)) + Sql_ShowDebug(sql_handle); + } + + ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); + return char_id; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1557,19 +1516,19 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag /*----------------------------------------------------------------------------------------------------------*/ int divorce_char_sql(int partner_id1, int partner_id2) { - unsigned char buf[64]; + unsigned char buf[64]; - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2)) + Sql_ShowDebug(sql_handle); - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = partner_id1; - WBUFL(buf,6) = partner_id2; - mapif_sendall(buf,10); + WBUFW(buf,0) = 0x2b12; + WBUFL(buf,2) = partner_id1; + WBUFL(buf,6) = partner_id2; + mapif_sendall(buf,10); - return 0; + return 0; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1580,151 +1539,159 @@ int divorce_char_sql(int partner_id1, int partner_id2) */ int delete_char_sql(int char_id) { - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. - int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); - Sql_FreeResult(sql_handle); - return -1; - } - - Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 1, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); party_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); guild_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); hom_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data); - - Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); - Sql_FreeResult(sql_handle); - - //check for config char del condition [Lupus] - // TODO: Move this out to packet processing (0x68/0x1fb). - if( ( char_del_level > 0 && base_level >= char_del_level ) - || ( char_del_level < 0 && base_level <= -char_del_level ) - ) { - ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); - return -1; - } - - /* Divorce [Wizputer] */ - if( partner_id ) - divorce_char_sql(char_id, partner_id); - - /* De-addopt [Zephyrus] */ - if( father_id || mother_id ) - { // Char is Baby - unsigned char buf[64]; - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b25; - WBUFL(buf,2) = father_id; - WBUFL(buf,6) = mother_id; - WBUFL(buf,10) = char_id; // Baby - mapif_sendall(buf,14); - } - - //Make the character leave the party [Skotlex] - if (party_id) - inter_party_leave(party_id, account_id, char_id); - - /* delete char's pet */ - //Delete the hatched pet if you have one... - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Delete all pets that are stored in eggs (inventory + cart) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* remove homunculus */ - if( hom_id ) - mapif_homunculus_delete(hom_id); - - /* remove mercenary data */ - mercenary_owner_delete(char_id); - - /* delete char's friends list */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete char from other's friend list */ - //NOTE: Won't this cause problems for people who are already online? [Skotlex] - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. + int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; + char *data; + size_t len; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); + Sql_FreeResult(sql_handle); + return -1; + } + + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 1, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + party_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + guild_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + hom_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + partner_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + father_id = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + mother_id = atoi(data); + + Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); + Sql_FreeResult(sql_handle); + + //check for config char del condition [Lupus] + // TODO: Move this out to packet processing (0x68/0x1fb). + if ((char_del_level > 0 && base_level >= char_del_level) + || (char_del_level < 0 && base_level <= -char_del_level) + ) { + ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); + return -1; + } + + /* Divorce [Wizputer] */ + if (partner_id) + divorce_char_sql(char_id, partner_id); + + /* De-addopt [Zephyrus] */ + if (father_id || mother_id) { + // Char is Baby + unsigned char buf[64]; + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id)) + Sql_ShowDebug(sql_handle); + + WBUFW(buf,0) = 0x2b25; + WBUFL(buf,2) = father_id; + WBUFL(buf,6) = mother_id; + WBUFL(buf,10) = char_id; // Baby + mapif_sendall(buf,14); + } + + //Make the character leave the party [Skotlex] + if (party_id) + inter_party_leave(party_id, account_id, char_id); + + /* delete char's pet */ + //Delete the hatched pet if you have one... + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id)) + Sql_ShowDebug(sql_handle); + + //Delete all pets that are stored in eggs (inventory + cart) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* remove homunculus */ + if (hom_id) + mapif_homunculus_delete(hom_id); + + /* remove mercenary data */ + mercenary_owner_delete(char_id); + + /* delete char's friends list */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete char from other's friend list */ + //NOTE: Won't this cause problems for people who are already online? [Skotlex] + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id)) + Sql_ShowDebug(sql_handle); #ifdef HOTKEY_SAVING - /* delete hotkeys */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) - Sql_ShowDebug(sql_handle); + /* delete hotkeys */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id)) + Sql_ShowDebug(sql_handle); #endif - /* delete inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete cart inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete memo areas */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete character registry */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete skills */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) - Sql_ShowDebug(sql_handle); - + /* delete inventory */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete cart inventory */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete memo areas */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete character registry */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete skills */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id)) + Sql_ShowDebug(sql_handle); + #ifdef ENABLE_SC_SAVING - /* status changes */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); + /* status changes */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); #endif - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", - charlog_db, account_id, 0, char_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - /* delete character */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* No need as we used inter_guild_leave [Skotlex] - // Also delete info from guildtables. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) - Sql_ShowDebug(sql_handle); - */ - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - mapif_parse_BreakGuild(0,guild_id); - else if( guild_id ) - inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. - return 0; + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", + charlog_db, account_id, 0, char_id, esc_name)) + Sql_ShowDebug(sql_handle); + } + + /* delete character */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* No need as we used inter_guild_leave [Skotlex] + // Also delete info from guildtables. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) + Sql_ShowDebug(sql_handle); + */ + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) + mapif_parse_BreakGuild(0,guild_id); + else if (guild_id) + inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. + return 0; } //--------------------------------------------------------------------- @@ -1732,190 +1699,187 @@ int delete_char_sql(int char_id) //--------------------------------------------------------------------- int count_users(void) { - int i, users; - - users = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - if (server[i].fd > 0) { - users += server[i].users; - } - } - return users; + int i, users; + + users = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + if (server[i].fd > 0) { + users += server[i].users; + } + } + return users; } // Writes char data to the buffer in the format used by the client. // Used in packets 0x6b (chars info) and 0x6d (new char info) // Returns the size #define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) -int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) +int mmo_char_tobuf(uint8 *buffer, struct mmo_charstatus *p) { - unsigned short offset = 0; - uint8* buf; - - if( buffer == NULL || p == NULL ) - return 0; - - buf = WBUFP(buffer,0); - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, INT32_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, INT32_MAX); - WBUFL(buf,16) = p->job_level; - WBUFL(buf,20) = 0; // probably opt1 - WBUFL(buf,24) = 0; // probably opt2 - WBUFL(buf,28) = p->option; - WBUFL(buf,32) = p->karma; - WBUFL(buf,36) = p->manner; - WBUFW(buf,40) = min(p->status_point, INT16_MAX); - WBUFL(buf,42) = p->hp; - WBUFL(buf,46) = p->max_hp; - offset+=4; - buf = WBUFP(buffer,offset); - WBUFW(buf,46) = min(p->sp, INT16_MAX); - WBUFW(buf,48) = min(p->max_sp, INT16_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - - //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; - - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, INT16_MAX); - WBUFW(buf,62) = p->head_bottom; - WBUFW(buf,64) = p->shield; - WBUFW(buf,66) = p->head_top; - WBUFW(buf,68) = p->head_mid; - WBUFW(buf,70) = p->hair_color; - WBUFW(buf,72) = p->clothes_color; - memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); - WBUFB(buf,98) = min(p->str, UINT8_MAX); - WBUFB(buf,99) = min(p->agi, UINT8_MAX); - WBUFB(buf,100) = min(p->vit, UINT8_MAX); - WBUFB(buf,101) = min(p->int_, UINT8_MAX); - WBUFB(buf,102) = min(p->dex, UINT8_MAX); - WBUFB(buf,103) = min(p->luk, UINT8_MAX); - WBUFW(buf,104) = p->slot; - WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1; - offset += 2; + unsigned short offset = 0; + uint8 *buf; + + if (buffer == NULL || p == NULL) + return 0; + + buf = WBUFP(buffer,0); + WBUFL(buf,0) = p->char_id; + WBUFL(buf,4) = min(p->base_exp, INT32_MAX); + WBUFL(buf,8) = p->zeny; + WBUFL(buf,12) = min(p->job_exp, INT32_MAX); + WBUFL(buf,16) = p->job_level; + WBUFL(buf,20) = 0; // probably opt1 + WBUFL(buf,24) = 0; // probably opt2 + WBUFL(buf,28) = p->option; + WBUFL(buf,32) = p->karma; + WBUFL(buf,36) = p->manner; + WBUFW(buf,40) = min(p->status_point, INT16_MAX); + WBUFL(buf,42) = p->hp; + WBUFL(buf,46) = p->max_hp; + offset+=4; + buf = WBUFP(buffer,offset); + WBUFW(buf,46) = min(p->sp, INT16_MAX); + WBUFW(buf,48) = min(p->max_sp, INT16_MAX); + WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; + WBUFW(buf,52) = p->class_; + WBUFW(buf,54) = p->hair; + + //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; + + WBUFW(buf,58) = p->base_level; + WBUFW(buf,60) = min(p->skill_point, INT16_MAX); + WBUFW(buf,62) = p->head_bottom; + WBUFW(buf,64) = p->shield; + WBUFW(buf,66) = p->head_top; + WBUFW(buf,68) = p->head_mid; + WBUFW(buf,70) = p->hair_color; + WBUFW(buf,72) = p->clothes_color; + memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); + WBUFB(buf,98) = min(p->str, UINT8_MAX); + WBUFB(buf,99) = min(p->agi, UINT8_MAX); + WBUFB(buf,100) = min(p->vit, UINT8_MAX); + WBUFB(buf,101) = min(p->int_, UINT8_MAX); + WBUFB(buf,102) = min(p->dex, UINT8_MAX); + WBUFB(buf,103) = min(p->luk, UINT8_MAX); + WBUFW(buf,104) = p->slot; + WBUFW(buf,106) = (p->rename > 0) ? 0 : 1; + offset += 2; #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803 - mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108)); - offset += MAP_NAME_LENGTH_EXT; + mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char *)WBUFP(buf,108)); + offset += MAP_NAME_LENGTH_EXT; #endif #if PACKETVER >= 20100803 - WBUFL(buf,124) = TOL(p->delete_date); - offset += 4; + WBUFL(buf,124) = TOL(p->delete_date); + offset += 4; #endif #if PACKETVER >= 20110111 - WBUFL(buf,128) = p->robe; - offset += 4; + WBUFL(buf,128) = p->robe; + offset += 4; #endif #if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. - #if PACKETVER >= 20110928 - WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) - offset += 4; - #endif - #if PACKETVER >= 20111025 - WBUFL(buf,136) = ( p->rename > 0 ) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) - offset += 4; - #endif +#if PACKETVER >= 20110928 + WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) + offset += 4; +#endif +#if PACKETVER >= 20111025 + WBUFL(buf,136) = (p->rename > 0) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) + offset += 4; +#endif #endif - return 106+offset; + return 106+offset; } //---------------------------------------- // Function to send characters to a player //---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd) +int mmo_char_send006b(int fd, struct char_session_data *sd) { - int j, offset = 0; + int j, offset = 0; #if PACKETVER >= 20100413 - offset += 3; + offset += 3; #endif - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); + if (save_log) + ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - j = 24 + offset; // offset - WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6b; + j = 24 + offset; // offset + WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6b; #if PACKETVER >= 20100413 - WFIFOB(fd,4) = MAX_CHARS; // Max slots. - WFIFOB(fd,5) = MAX_CHARS; // Available slots. - WFIFOB(fd,6) = MAX_CHARS; // Premium slots. + WFIFOB(fd,4) = MAX_CHARS; // Max slots. + WFIFOB(fd,5) = MAX_CHARS; // Available slots. + WFIFOB(fd,6) = MAX_CHARS; // Premium slots. #endif - memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); + memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes + j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); + WFIFOW(fd,2) = j; // packet len + WFIFOSET(fd,j); - return 0; + return 0; } int char_married(int pl1, int pl2) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( pl2 == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if (pl2 == atoi(data)) { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_child(int parent_id, int child_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( child_id == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if (child_id == atoi(data)) { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_family(int cid1, int cid2, int cid3) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) - Sql_ShowDebug(sql_handle); - else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int charid; - int partnerid; - int childid; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); charid = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data); - - if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) || - (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) || - (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) ) - { - Sql_FreeResult(sql_handle); - return childid; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3)) + Sql_ShowDebug(sql_handle); + else while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int charid; + int partnerid; + int childid; + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + charid = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + partnerid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + childid = atoi(data); + + if ((cid1 == charid && ((cid2 == partnerid && cid3 == childid) || (cid2 == childid && cid3 == partnerid))) || + (cid1 == partnerid && ((cid2 == charid && cid3 == childid) || (cid2 == childid && cid3 == charid))) || + (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid)))) { + Sql_FreeResult(sql_handle); + return childid; + } + } + Sql_FreeResult(sql_handle); + return 0; } //---------------------------------------------------------------------- @@ -1923,58 +1887,58 @@ int char_family(int cid1, int cid2, int cid3) //---------------------------------------------------------------------- void disconnect_player(int account_id) { - int i; - struct char_session_data* sd; + int i; + struct char_session_data *sd; - // disconnect player if online on char-server - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id ); - if( i < fd_max ) - set_eof(i); + // disconnect player if online on char-server + ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->account_id == account_id); + if (i < fd_max) + set_eof(i); } static void char_auth_ok(int fd, struct char_session_data *sd) { - struct online_char_data* character; - - if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) - { // check if character is not online already. [Skotlex] - if (character->server > -1) - { //Character already online. KICK KICK KICK - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - if (character->fd >= 0 && character->fd != fd) - { //There's already a connection from this account that hasn't picked a char yet. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request account data - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } - - // mark session as 'authed' - sd->auth = true; - - // set char online on charserver - set_char_charselect(sd->account_id); - - // continues when account data is received... + struct online_char_data *character; + + if ((character = (struct online_char_data *)idb_get(online_char_db, sd->account_id)) != NULL) { + // check if character is not online already. [Skotlex] + if (character->server > -1) { + //Character already online. KICK KICK KICK + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + if (character->fd >= 0 && character->fd != fd) { + //There's already a connection from this account that hasn't picked a char yet. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + character->fd = fd; + } + + if (login_fd > 0) { + // request account data + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2716; + WFIFOL(login_fd,2) = sd->account_id; + WFIFOSET(login_fd,6); + } + + // mark session as 'authed' + sd->auth = true; + + // set char online on charserver + set_char_charselect(sd->account_id); + + // continues when account data is received... } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); @@ -1984,12 +1948,12 @@ void mapif_server_reset(int id); /// Resets all the data. void loginif_reset(void) { - int id; - // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - flush_fifos(); - exit(EXIT_FAILURE); + int id; + // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + mapif_server_reset(id); + flush_fifos(); + exit(EXIT_FAILURE); } @@ -1998,366 +1962,361 @@ void loginif_reset(void) /// If all the conditions are met, it stops the core loop. void loginif_check_shutdown(void) { - if( runflag != CHARSERVER_ST_SHUTDOWN ) - return; - runflag = CORE_ST_STOP; + if (runflag != CHARSERVER_ST_SHUTDOWN) + return; + runflag = CORE_ST_STOP; } /// Called when the connection to Login Server is disconnected. void loginif_on_disconnect(void) { - ShowWarning("Connection to Login Server lost.\n\n"); + ShowWarning("Connection to Login Server lost.\n\n"); } /// Called when all the connection steps are completed. void loginif_on_ready(void) { - int i; + int i; - loginif_check_shutdown(); - - //Send online accounts to login server. - send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); + loginif_check_shutdown(); - // if no map-server already connected, display a message... - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] ); - if( i == ARRAYLENGTH(server) ) - ShowStatus("Awaiting maps from map-server.\n"); + //Send online accounts to login server. + send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); + + // if no map-server already connected, display a message... + ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0]); + if (i == ARRAYLENGTH(server)) + ShowStatus("Awaiting maps from map-server.\n"); } -int parse_fromlogin(int fd) { - struct char_session_data* sd = NULL; - int i; - - // only process data from the login-server - if( fd != login_fd ) { - ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) { - do_close(fd); - login_fd = -1; - loginif_on_disconnect(); - return 0; - } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ - if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ - set_eof(fd); - return 0; - } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ - WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) - WFIFOW(fd,0) = 0x2719; - WFIFOSET(fd,2); - - session[fd]->flag.ping = 2; - } - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while(RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - // acknowledgement of connect-to-loginserver request - case 0x2711: - if (RFIFOREST(fd) < 3) - return 0; - - if (RFIFOB(fd,2)) { - //printf("connect login server error : %d\n", RFIFOB(fd,2)); - ShowError("Can not connect to login-server.\n"); - ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); - ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); - set_eof(fd); - return 0; - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - loginif_on_ready(); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 25) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - uint8 result = RFIFOB(fd,15); - int request_id = RFIFOL(fd,16); - uint32 version = RFIFOL(fd,20); - uint8 clienttype = RFIFOB(fd,24); - RFIFOSKIP(fd,25); - - if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && - !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) - { - int client_fd = request_id; - sd->version = version; - sd->clienttype = clienttype; - switch( result ) - { - case 0:// ok - char_auth_ok(client_fd, sd); - break; - case 1:// auth failed - WFIFOHEAD(client_fd,3); - WFIFOW(client_fd,0) = 0x6c; - WFIFOB(client_fd,2) = 0;// rejected from server - WFIFOSET(client_fd,3); - break; - } - } - } - break; - - case 0x2717: // account data - if (RFIFOREST(fd) < 62) - return 0; - - // find the authenticated session with this account id - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); - if( i < fd_max ) - { - int server_id; - memcpy(sd->email, RFIFOP(fd,6), 40); - sd->expiration_time = (time_t)RFIFOL(fd,46); - sd->group_id = RFIFOB(fd,50); - safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate)); - ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); - // continued from char_auth_ok... - if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 - ( max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) { - // refuse connection (over populated) - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOW(i,2) = 0; - WFIFOSET(i,3); - } else { - // send characters to player - mmo_char_send006b(i, sd); +int parse_fromlogin(int fd) +{ + struct char_session_data *sd = NULL; + int i; + + // only process data from the login-server + if (fd != login_fd) { + ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); + do_close(fd); + return 0; + } + + if (session[fd]->flag.eof) { + do_close(fd); + login_fd = -1; + loginif_on_disconnect(); + return 0; + } else if (session[fd]->flag.ping) { /* we've reached stall time */ + if (DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2)) { /* we can't wait any longer */ + set_eof(fd); + return 0; + } else if (session[fd]->flag.ping != 2) { /* we haven't sent ping out yet */ + WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) + WFIFOW(fd,0) = 0x2719; + WFIFOSET(fd,2); + + session[fd]->flag.ping = 2; + } + } + + sd = (struct char_session_data *)session[fd]->session_data; + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + // acknowledgement of connect-to-loginserver request + case 0x2711: + if (RFIFOREST(fd) < 3) + return 0; + + if (RFIFOB(fd,2)) { + //printf("connect login server error : %d\n", RFIFOB(fd,2)); + ShowError("Can not connect to login-server.\n"); + ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); + ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); + ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); + set_eof(fd); + return 0; + } else { + ShowStatus("Connected to login-server (connection #%d).\n", fd); + loginif_on_ready(); + } + RFIFOSKIP(fd,3); + break; + + // acknowledgement of account authentication request + case 0x2713: + if (RFIFOREST(fd) < 25) + return 0; + { + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + uint8 result = RFIFOB(fd,15); + int request_id = RFIFOL(fd,16); + uint32 version = RFIFOL(fd,20); + uint8 clienttype = RFIFOB(fd,24); + RFIFOSKIP(fd,25); + + if (session_isActive(request_id) && (sd=(struct char_session_data *)session[request_id]->session_data) && + !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex) { + int client_fd = request_id; + sd->version = version; + sd->clienttype = clienttype; + switch (result) { + case 0:// ok + char_auth_ok(client_fd, sd); + break; + case 1:// auth failed + WFIFOHEAD(client_fd,3); + WFIFOW(client_fd,0) = 0x6c; + WFIFOB(client_fd,2) = 0;// rejected from server + WFIFOSET(client_fd,3); + break; + } + } + } + break; + + case 0x2717: // account data + if (RFIFOREST(fd) < 62) + return 0; + + // find the authenticated session with this account id + ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2)); + if (i < fd_max) { + int server_id; + memcpy(sd->email, RFIFOP(fd,6), 40); + sd->expiration_time = (time_t)RFIFOL(fd,46); + sd->group_id = RFIFOB(fd,50); + safestrncpy(sd->birthdate, (const char *)RFIFOP(fd,51), sizeof(sd->birthdate)); + ARR_FIND(0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0]); + // continued from char_auth_ok... + if (server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 + (max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group)) { + // refuse connection (over populated) + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x6c; + WFIFOW(i,2) = 0; + WFIFOSET(i,3); + } else { + // send characters to player + mmo_char_send006b(i, sd); #if PACKETVER >= 20110309 - // PIN code system, disabled - WFIFOHEAD(i, 12); - WFIFOW(i, 0) = 0x08B9; - WFIFOW(i, 2) = 0; - WFIFOW(i, 4) = 0; - WFIFOL(i, 6) = sd->account_id; - WFIFOW(i, 10) = 0; - WFIFOSET(i, 12); + // PIN code system, disabled + WFIFOHEAD(i, 12); + WFIFOW(i, 0) = 0x08B9; + WFIFOW(i, 2) = 0; + WFIFOW(i, 4) = 0; + WFIFOL(i, 6) = sd->account_id; + WFIFOW(i, 10) = 0; + WFIFOSET(i, 12); #endif - } - } - RFIFOSKIP(fd,62); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - session[fd]->flag.ping = 0; - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if( acc > 0 ) - {// TODO: Is this even possible? - int char_id[MAX_CHARS]; - int class_[MAX_CHARS]; - int guild_id[MAX_CHARS]; - int num; - char* data; - - struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); - if( node != NULL ) - node->sex = sex; - - // get characters - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data); - } - num = i; - for( i = 0; i < num; ++i ) - { - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER || - class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || - class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || - class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || - class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || - class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || - class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) - { - // job modification - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ) - class_[i] = (sex ? JOB_BARD : JOB_DANCER); - else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ) - class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); - else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ) - class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); - else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ) - class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); - else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ) - class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); - else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ) - class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); - else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) - class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); - } - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) ) - Sql_ShowDebug(sql_handle); - - if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); - } - Sql_FreeResult(sql_handle); - - // disconnect player if online on char-server - disconnect_player(acc); - } - - // notify all mapservers about this change - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - // reply to an account_reg2 registry request - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - { //Receive account_reg2 registry, forward to map servers. - unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; - memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] - mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP(fd, RFIFOW(fd,2)); - } - break; - - // State change of account/ban notification (from login-server) - case 0x2731: - if (RFIFOREST(fd) < 11) - return 0; - - { // send to all map-servers to disconnect the player - unsigned char buf[11]; - WBUFW(buf,0) = 0x2b14; - WBUFL(buf,2) = RFIFOL(fd,2); - WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban - WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment - mapif_sendall(buf, 11); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - - RFIFOSKIP(fd,11); - break; - - // Login server request to kick a character out. [Skotlex] - case 0x2734: - if (RFIFOREST(fd) < 6) - return 0; - { - int aid = RFIFOL(fd,2); - struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); - RFIFOSKIP(fd,6); - if( character != NULL ) - {// account is already marked as online! - if( character->server > -1 ) - { //Kick it from the map server it is on. - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); - } - else - {// Manual kick from char server. - struct char_session_data *tsd; - int i; - ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); - if( i < fd_max ) - { - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x81; - WFIFOB(i,2) = 2; // "Someone has already logged in with this id" - WFIFOSET(i,3); - set_eof(i); - } - else // still moving to the map-server - set_char_offline(-1, aid); - } - } - idb_remove(auth_db, aid);// reject auth attempts from map-server - } - break; - - // ip address update signal from login server - case 0x2735: - { - unsigned char buf[2]; - uint32 new_ip = 0; - - WBUFW(buf,0) = 0x2b1e; - mapif_sendall(buf, 2); - - new_ip = host2ip(login_ip_str); - if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login ip, too. - - new_ip = host2ip(char_ip_str); - if (new_ip && new_ip != char_ip) - { //Update ip. - char_ip = new_ip; - ShowInfo("Updating IP for [%s].\n", char_ip_str); - // notify login server about the change - WFIFOHEAD(fd,6); - WFIFOW(fd,0) = 0x2736; - WFIFOL(fd,2) = htonl(char_ip); - WFIFOSET(fd,6); - } - - RFIFOSKIP(fd,2); - } - break; - - default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + } + } + RFIFOSKIP(fd,62); + break; + + // login-server alive packet + case 0x2718: + if (RFIFOREST(fd) < 2) + return 0; + RFIFOSKIP(fd,2); + session[fd]->flag.ping = 0; + break; + + // changesex reply + case 0x2723: + if (RFIFOREST(fd) < 7) + return 0; + { + unsigned char buf[7]; + + int acc = RFIFOL(fd,2); + int sex = RFIFOB(fd,6); + RFIFOSKIP(fd,7); + + if (acc > 0) { + // TODO: Is this even possible? + int char_id[MAX_CHARS]; + int class_[MAX_CHARS]; + int guild_id[MAX_CHARS]; + int num; + char *data; + + struct auth_node *node = (struct auth_node *)idb_get(auth_db, acc); + if (node != NULL) + node->sex = sex; + + // get characters + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + Sql_GetData(sql_handle, 0, &data, NULL); + char_id[i] = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + class_[i] = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + guild_id[i] = atoi(data); + } + num = i; + for (i = 0; i < num; ++i) { + if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER || + class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || + class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || + class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || + class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || + class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || + class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) { + // job modification + if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER) + class_[i] = (sex ? JOB_BARD : JOB_DANCER); + else if (class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY) + class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); + else if (class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER) + class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); + else if (class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER) + class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); + else if (class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T) + class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); + else if (class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER) + class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); + else if (class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) + class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); + } + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i])) + Sql_ShowDebug(sql_handle); + + if (guild_id[i]) // If there is a guild, update the guild_member data [Skotlex] + inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); + } + Sql_FreeResult(sql_handle); + + // disconnect player if online on char-server + disconnect_player(acc); + } + + // notify all mapservers about this change + WBUFW(buf,0) = 0x2b0d; + WBUFL(buf,2) = acc; + WBUFB(buf,6) = sex; + mapif_sendall(buf, 7); + } + break; + + // reply to an account_reg2 registry request + case 0x2729: + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + { + //Receive account_reg2 registry, forward to map servers. + unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; + memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] + mapif_sendall(buf, WBUFW(buf,2)); + RFIFOSKIP(fd, RFIFOW(fd,2)); + } + break; + + // State change of account/ban notification (from login-server) + case 0x2731: + if (RFIFOREST(fd) < 11) + return 0; + + { + // send to all map-servers to disconnect the player + unsigned char buf[11]; + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = RFIFOL(fd,2); + WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban + WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment + mapif_sendall(buf, 11); + } + // disconnect player if online on char-server + disconnect_player(RFIFOL(fd,2)); + + RFIFOSKIP(fd,11); + break; + + // Login server request to kick a character out. [Skotlex] + case 0x2734: + if (RFIFOREST(fd) < 6) + return 0; + { + int aid = RFIFOL(fd,2); + struct online_char_data *character = (struct online_char_data *)idb_get(online_char_db, aid); + RFIFOSKIP(fd,6); + if (character != NULL) { + // account is already marked as online! + if (character->server > -1) { + //Kick it from the map server it is on. + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); + } else { + // Manual kick from char server. + struct char_session_data *tsd; + int i; + ARR_FIND(0, fd_max, i, session[i] && (tsd = (struct char_session_data *)session[i]->session_data) && tsd->account_id == aid); + if (i < fd_max) { + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x81; + WFIFOB(i,2) = 2; // "Someone has already logged in with this id" + WFIFOSET(i,3); + set_eof(i); + } else // still moving to the map-server + set_char_offline(-1, aid); + } + } + idb_remove(auth_db, aid);// reject auth attempts from map-server + } + break; + + // ip address update signal from login server + case 0x2735: { + unsigned char buf[2]; + uint32 new_ip = 0; + + WBUFW(buf,0) = 0x2b1e; + mapif_sendall(buf, 2); + + new_ip = host2ip(login_ip_str); + if (new_ip && new_ip != login_ip) + login_ip = new_ip; //Update login ip, too. + + new_ip = host2ip(char_ip_str); + if (new_ip && new_ip != char_ip) { + //Update ip. + char_ip = new_ip; + ShowInfo("Updating IP for [%s].\n", char_ip_str); + // notify login server about the change + WFIFOHEAD(fd,6); + WFIFOW(fd,0) = 0x2736; + WFIFOL(fd,2) = htonl(char_ip); + WFIFOSET(fd,6); + } + + RFIFOSKIP(fd,2); + } + break; + + default: + ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data); @@ -2365,176 +2324,169 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); void do_init_loginif(void) { - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour + // establish char-login connection if not present + add_timer_func_list(check_connect_login_server, "check_connect_login_server"); + add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); + + // send a list of all online account IDs to login server + add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); + add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour } void do_final_loginif(void) { - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } + if (login_fd != -1) { + do_close(login_fd); + login_fd = -1; + } } int request_accreg2(int account_id, int char_id) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x272e; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = char_id; + WFIFOSET(login_fd,10); + return 1; + } + return 0; } //Send packet forward to login-server for account saving -int save_accreg2(unsigned char* buf, int len) +int save_accreg2(unsigned char *buf, int len) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,len+4); + memcpy(WFIFOP(login_fd,4), buf, len); + WFIFOW(login_fd,0) = 0x2728; + WFIFOW(login_fd,2) = len+4; + WFIFOSET(login_fd,len+4); + return 1; + } + return 0; } void char_read_fame_list(void) { - int i; - char* data; - size_t len; - - // Empty ranking lists - memset(smith_fame_list, 0, sizeof(smith_fame_list)); - memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); - memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); - // Build Blacksmith ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - smith_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - smith_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Alchemist ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - chemist_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - chemist_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Taekwon ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - taekwon_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - taekwon_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - Sql_FreeResult(sql_handle); + int i; + char *data; + size_t len; + + // Empty ranking lists + memset(smith_fame_list, 0, sizeof(smith_fame_list)); + memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); + memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); + // Build Blacksmith ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + smith_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + smith_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Alchemist ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + chemist_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + chemist_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Taekwon ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + taekwon_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + taekwon_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + Sql_FreeResult(sql_handle); } // Send map-servers the fame ranking lists int char_send_fame_list(int fd) { - int i, len = 8; - unsigned char buf[32000]; - - WBUFW(buf,0) = 0x2b1b; - - for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if (fd != -1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; + int i, len = 8; + unsigned char buf[32000]; + + WBUFW(buf,0) = 0x2b1b; + + for (i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add blacksmith's block length + WBUFW(buf, 6) = len; + + for (i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add alchemist's block length + WBUFW(buf, 4) = len; + + for (i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add total packet length + WBUFW(buf, 2) = len; + + if (fd != -1) + mapif_send(fd, buf, len); + else + mapif_sendall(buf, len); + + return 0; } void char_update_fame_list(int type, int index, int fame) { - unsigned char buf[8]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); + unsigned char buf[8]; + WBUFW(buf,0) = 0x2b22; + WBUFB(buf,2) = type; + WBUFB(buf,3) = index; + WBUFL(buf,4) = fame; + mapif_sendall(buf, 8); } //Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) //Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) -int char_loadName(int char_id, char* name) +int char_loadName(int char_id, char *name) { - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, &len); - safestrncpy(name, data, NAME_LENGTH); - return 1; - } - else - { - safestrncpy(name, unknown_char_name, NAME_LENGTH); - } - return 0; + char *data; + size_t len; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); + return 1; + } else { + safestrncpy(name, unknown_char_name, NAME_LENGTH); + } + return 0; } int search_mapserver(unsigned short map, uint32 ip, uint16 port); @@ -2543,833 +2495,825 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port); /// Initializes a server structure. void mapif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void mapif_server_destroy(int id) { - if( server[id].fd == -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } + if (server[id].fd == -1) { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void mapif_server_reset(int id) { - int i,j; - unsigned char buf[16384]; - int fd = server[id].fd; - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd) ) - Sql_ShowDebug(sql_handle); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - mapif_server_destroy(id); - mapif_server_init(id); + int i,j; + unsigned char buf[16384]; + int fd = server[id].fd; + //Notify other map servers that this one is gone. [Skotlex] + WBUFW(buf,0) = 0x2b20; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + j = 0; + for (i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[id].map[i]) + WBUFW(buf,10+(j++)*4) = server[id].map[i]; + if (j > 0) { + WBUFW(buf,2) = j * 4 + 10; + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd)) + Sql_ShowDebug(sql_handle); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. + mapif_server_destroy(id); + mapif_server_init(id); } /// Called when the connection to a Map Server is disconnected. void mapif_on_disconnect(int id) { - ShowStatus("Map-server #%d has disconnected.\n", id); - mapif_server_reset(id); + ShowStatus("Map-server #%d has disconnected.\n", id); + mapif_server_reset(id); } int parse_frommap(int fd) { - int i, j; - int id; - - ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); - if( id == ARRAYLENGTH(server) ) - {// not a map server - ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); - do_close(fd); - return 0; - } - if( session[fd]->flag.eof ) - { - do_close(fd); - server[id].fd = -1; - mapif_on_disconnect(id); - return 0; - } - - while(RFIFOREST(fd) >= 2) - { - switch(RFIFOW(fd,0)) - { - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - memset(server[id].map, 0, sizeof(server[id].map)); - j = 0; - for(i = 4; i < RFIFOW(fd,2); i += 4) { - server[id].map[j] = RFIFOW(fd,i); - j++; - } - - ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, CONVIP(server[id].ip), server[id].port); - ShowStatus("Map-server %d loading complete.\n", id); - - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; - memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - - char_send_fame_list(fd); //Send fame list. - - { - unsigned char buf[16384]; - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - } else { - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for(x = 0; x < ARRAYLENGTH(server); x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for(i = 0; i < ARRAYLENGTH(server[x].map); i++) - if (server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - if (RFIFOREST(fd) < 10) - return 0; - { + int i, j; + int id; + + ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); + if (id == ARRAYLENGTH(server)) { + // not a map server + ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); + do_close(fd); + return 0; + } + if (session[fd]->flag.eof) { + do_close(fd); + server[id].fd = -1; + mapif_on_disconnect(id); + return 0; + } + + while (RFIFOREST(fd) >= 2) { + switch (RFIFOW(fd,0)) { + + case 0x2afa: // Receiving map names list from the map-server + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + memset(server[id].map, 0, sizeof(server[id].map)); + j = 0; + for (i = 4; i < RFIFOW(fd,2); i += 4) { + server[id].map[j] = RFIFOW(fd,i); + j++; + } + + ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", + id, j, CONVIP(server[id].ip), server[id].port); + ShowStatus("Map-server %d loading complete.\n", id); + + // send name for wisp to player + WFIFOHEAD(fd, 3 + NAME_LENGTH); + WFIFOW(fd,0) = 0x2afb; + WFIFOB(fd,2) = 0; + memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); + WFIFOSET(fd,3+NAME_LENGTH); + + char_send_fame_list(fd); //Send fame list. + + { + unsigned char buf[16384]; + int x; + if (j == 0) { + ShowWarning("Map-server %d has NO maps.\n", id); + } else { + // Transmitting maps information to the other map-servers + WBUFW(buf,0) = 0x2b04; + WBUFW(buf,2) = j * 4 + 10; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + // Transmitting the maps of the other map-servers to the new map-server + for (x = 0; x < ARRAYLENGTH(server); x++) { + if (server[x].fd > 0 && x != id) { + WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); + WFIFOW(fd,0) = 0x2b04; + WFIFOL(fd,4) = htonl(server[x].ip); + WFIFOW(fd,8) = htons(server[x].port); + j = 0; + for (i = 0; i < ARRAYLENGTH(server[x].map); i++) + if (server[x].map[i]) + WFIFOW(fd,10+(j++)*4) = server[x].map[i]; + if (j > 0) { + WFIFOW(fd,2) = j * 4 + 10; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] + if (RFIFOREST(fd) < 10) + return 0; + { #ifdef ENABLE_SC_SAVING - int aid, cid; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", - scdata_db, aid, cid) ) - { - Sql_ShowDebug(sql_handle); - break; - } - if( Sql_NumRows(sql_handle) > 0 ) - { - struct status_change_data scdata; - int count; - char* data; - - WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); - WFIFOW(fd,0) = 0x2b1d; - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count ) - { - Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); - memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); - } - if (count >= 50) - ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); - if (count > 0) - { - WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); - WFIFOW(fd,12) = count; - WFIFOSET(fd,WFIFOW(fd,2)); - - //Clear the data once loaded. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) - Sql_ShowDebug(sql_handle); - } - } - Sql_FreeResult(sql_handle); + int aid, cid; + aid = RFIFOL(fd,2); + cid = RFIFOL(fd,6); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", + scdata_db, aid, cid)) { + Sql_ShowDebug(sql_handle); + break; + } + if (Sql_NumRows(sql_handle) > 0) { + struct status_change_data scdata; + int count; + char *data; + + WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); + WFIFOW(fd,0) = 0x2b1d; + WFIFOL(fd,4) = aid; + WFIFOL(fd,8) = cid; + for (count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count) { + Sql_GetData(sql_handle, 0, &data, NULL); + scdata.type = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + scdata.tick = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + scdata.val1 = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + scdata.val2 = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + scdata.val3 = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + scdata.val4 = atoi(data); + memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); + } + if (count >= 50) + ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); + if (count > 0) { + WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); + WFIFOW(fd,12) = count; + WFIFOSET(fd,WFIFOW(fd,2)); + + //Clear the data once loaded. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid)) + Sql_ShowDebug(sql_handle); + } + } + Sql_FreeResult(sql_handle); #endif - RFIFOSKIP(fd, 10); - } - break; - - case 0x2afe: //set MAP user count - if (RFIFOREST(fd) < 4) - return 0; - if (RFIFOW(fd,2) != server[id].users) { - server[id].users = RFIFOW(fd,2); - ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); - } - RFIFOSKIP(fd, 4); - break; - - case 0x2aff: //set MAP users - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - //TODO: When data mismatches memory, update guild/party online/offline states. - int aid, cid; - struct online_char_data* character; - - server[id].users = RFIFOW(fd,4); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' - for(i = 0; i < server[id].users; i++) { - aid = RFIFOL(fd,6+i*8); - cid = RFIFOL(fd,6+i*8+4); - character = idb_ensure(online_char_db, aid, create_online_char_data); - if( character->server > -1 && character->server != id ) - { - ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, id, aid, cid); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - character->server = id; - character->char_id = cid; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); - struct online_char_data* character; - - if (size - 13 != sizeof(struct mmo_charstatus)) - { - ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); - RFIFOSKIP(fd,size); - break; - } - //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || ( - (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && - character->char_id == cid)) - { - struct mmo_charstatus char_dat; - memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - mmo_char_tosql(cid, &char_dat); - } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. - ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); - set_char_online(id, cid, aid); - } - - if (RFIFOB(fd,12)) - { //Flag, set character offline after saving. [Skotlex] - set_char_offline(cid, aid); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = aid; - WFIFOL(fd,6) = cid; - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,size); - } - break; - - case 0x2b02: // req char selection - if( RFIFOREST(fd) < 18 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint32 ip = RFIFOL(fd,14); - RFIFOSKIP(fd,18); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0;// not ok - WFIFOSET(fd,7); - } - else - { - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = account_id; - node->char_id = 0; - node->login_id1 = login_id1; - node->login_id2 = login_id2; - //node->sex = 0; - node->ip = ntohl(ip); - //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - //node->gmlevel = 0; - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_charselect(account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 1;// ok - WFIFOSET(fd,7); - } - } - break; - - case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 39) - return 0; - { - int map_id, map_fd = -1; - struct online_char_data* data; - struct mmo_charstatus* char_data; - struct mmo_charstatus char_dat; - - map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. - if (map_id >= 0) - map_fd = server[map_id].fd; - //Char should just had been saved before this packet, so this should be safe. [Skotlex] - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - if (char_data == NULL) { //Really shouldn't happen. - mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - } - - if( runflag == CHARSERVER_ST_RUNNING && - session_isActive(map_fd) && - char_data ) - { //Send the map server the auth of this player. - struct auth_node* node; - - //Update the "last map" as this is where the player must be spawned on the new map server. - char_data->last_point.map = RFIFOW(fd,18); - char_data->last_point.x = RFIFOW(fd,20); - char_data->last_point.y = RFIFOW(fd,22); - char_data->sex = RFIFOB(fd,30); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = RFIFOL(fd,2); - node->char_id = RFIFOL(fd,14); - node->login_id1 = RFIFOL(fd,6); - node->login_id2 = RFIFOL(fd,10); - node->sex = RFIFOB(fd,30); - node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) - node->ip = ntohl(RFIFOL(fd,31)); - node->group_id = RFIFOL(fd,35); - node->changing_mapservers = 1; - idb_put(auth_db, RFIFOL(fd,2), node); - - data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); - data->char_id = char_data->char_id; - data->server = map_id; //Update server where char is. - - //Reply with an ack. - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOSET(fd,30); - } else { //Reply with nak - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOL(fd,6) = 0; //Set login1 to 0. - WFIFOSET(fd,30); - } - RFIFOSKIP(fd,39); - } - break; - - case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] - if (RFIFOREST(fd) < 10) - return 0; - { - int char_id, friend_id; - char_id = RFIFOL(fd,2); - friend_id = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", - friend_db, char_id, friend_id) ) { - Sql_ShowDebug(sql_handle); - break; - } - RFIFOSKIP(fd,10); - } - break; - - case 0x2b08: // char name request - if (RFIFOREST(fd) < 6) - return 0; - - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b09; - WFIFOL(fd,2) = RFIFOL(fd,2); - char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); - WFIFOSET(fd,30); - - RFIFOSKIP(fd,6); - break; - - case 0x2b0c: // Map server send information to change an email of an account -> login-server - if (RFIFOREST(fd) < 86) - return 0; - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,86); - memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) - if (RFIFOREST(fd) < 44) - return 0; - { - int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char esc_name[NAME_LENGTH*2+1]; - - int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) - const char* name = (char*)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban - short year = RFIFOW(fd,32); - short month = RFIFOW(fd,34); - short day = RFIFOW(fd,36); - short hour = RFIFOW(fd,38); - short minute = RFIFOW(fd,40); - short second = RFIFOW(fd,42); - RFIFOSKIP(fd,44); - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if( Sql_NumRows(sql_handle) == 0 ) - { - result = 1; // 1-player not found - } - else - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else - { - char name[NAME_LENGTH]; - int account_id; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - - if( login_fd <= 0 ) - result = 3; // 3-login-server offline - //FIXME: need to move this check to login server [ultramage] -// else -// if( acc != -1 && isGM(acc) < isGM(account_id) ) -// result = 2; // 2-gm level too low - else - switch( type ) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - } - } - - Sql_FreeResult(sql_handle); - - // send answer if a player ask, not if the server ask - if( acc != -1 && type != 5) { // Don't send answer for changesex - WFIFOHEAD(fd,34); - WFIFOW(fd, 0) = 0x2b0f; - WFIFOL(fd, 2) = acc; - safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOW(fd,30) = type; - WFIFOW(fd,32) = result; - WFIFOSET(fd,34); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - if (RFIFOREST(fd) < 11) - return 0; - { - int cid = RFIFOL(fd, 2); - int fame = RFIFOL(fd, 6); - char type = RFIFOB(fd, 10); - int size; - struct fame_list* list; - int player_pos; - int fame_pos; - - switch(type) - { - case 1: size = fame_list_size_smith; list = smith_fame_list; break; - case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; - case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; - default: size = 0; list = NULL; break; - } - - ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player - ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be - - if( player_pos == size && fame_pos == size ) - ;// not on list and not enough fame to get on it - else if( fame_pos == player_pos ) - {// same position - list[player_pos].fame = fame; - char_update_fame_list(type, player_pos, fame); - } - else - {// move in the list - if( player_pos == size ) - {// new ranker - not in the list - ARR_MOVE(size - 1, fame_pos, list, struct fame_list); - list[fame_pos].id = cid; - list[fame_pos].fame = fame; - char_loadName(cid, list[fame_pos].name); - } - else - {// already in the list - if( fame_pos == size ) - --fame_pos;// move to the end of the list - ARR_MOVE(player_pos, fame_pos, list, struct fame_list); - list[fame_pos].fame = fame; - } - char_send_fame_list(-1); - } - - RFIFOSKIP(fd,11); - } - break; - - // Divorce chars - case 0x2b11: - if( RFIFOREST(fd) < 10 ) - return 0; - - divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b16: // Receive rates [Wizputer] - if( RFIFOREST(fd) < 14 ) - return 0; - { - char esc_server_name[sizeof(server_name)*2+1]; - - Sql_EscapeString(sql_handle, esc_server_name, server_name); - - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", - ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) ) - Sql_ShowDebug(sql_handle); - RFIFOSKIP(fd,14); - } - break; - - case 0x2b17: // Character disconnected set online 0 [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - case 0x2b19: // Character set online [Wizputer] - if (RFIFOREST(fd) < 10) - return 0; - set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b1a: // Build and send fame ranking lists [DracoRPG] - if (RFIFOREST(fd) < 2) - return 0; - char_read_fame_list(); - char_send_fame_list(-1); - RFIFOSKIP(fd,2); - break; - - case 0x2b1c: //Request to save status change data. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { + RFIFOSKIP(fd, 10); + } + break; + + case 0x2afe: //set MAP user count + if (RFIFOREST(fd) < 4) + return 0; + if (RFIFOW(fd,2) != server[id].users) { + server[id].users = RFIFOW(fd,2); + ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); + } + RFIFOSKIP(fd, 4); + break; + + case 0x2aff: //set MAP users + if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + //TODO: When data mismatches memory, update guild/party online/offline states. + int aid, cid; + struct online_char_data *character; + + server[id].users = RFIFOW(fd,4); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' + for (i = 0; i < server[id].users; i++) { + aid = RFIFOL(fd,6+i*8); + cid = RFIFOL(fd,6+i*8+4); + character = idb_ensure(online_char_db, aid, create_online_char_data); + if (character->server > -1 && character->server != id) { + ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, id, aid, cid); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + character->server = id; + character->char_id = cid; + } + //If any chars remain in -2, they will be cleaned in the cleanup timer. + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x2b01: // Receive character data from map-server for saving + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); + struct online_char_data *character; + + if (size - 13 != sizeof(struct mmo_charstatus)) { + ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); + RFIFOSKIP(fd,size); + break; + } + //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect + if (RFIFOB(fd,12) || ( + (character = (struct online_char_data *)idb_get(online_char_db, aid)) != NULL && + character->char_id == cid)) { + struct mmo_charstatus char_dat; + memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + mmo_char_tosql(cid, &char_dat); + } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. + ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); + set_char_online(id, cid, aid); + } + + if (RFIFOB(fd,12)) { + //Flag, set character offline after saving. [Skotlex] + set_char_offline(cid, aid); + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. + WFIFOL(fd,2) = aid; + WFIFOL(fd,6) = cid; + WFIFOSET(fd,10); + } + RFIFOSKIP(fd,size); + } + break; + + case 0x2b02: // req char selection + if (RFIFOREST(fd) < 18) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint32 ip = RFIFOL(fd,14); + RFIFOSKIP(fd,18); + + if (runflag != CHARSERVER_ST_RUNNING) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 0;// not ok + WFIFOSET(fd,7); + } else { + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = account_id; + node->char_id = 0; + node->login_id1 = login_id1; + node->login_id2 = login_id2; + //node->sex = 0; + node->ip = ntohl(ip); + //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) + //node->gmlevel = 0; + idb_put(auth_db, account_id, node); + + //Set char to "@ char select" in online db [Kevin] + set_char_charselect(account_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 1;// ok + WFIFOSET(fd,7); + } + } + break; + + case 0x2b05: // request "change map server" + if (RFIFOREST(fd) < 39) + return 0; + { + int map_id, map_fd = -1; + struct online_char_data *data; + struct mmo_charstatus *char_data; + struct mmo_charstatus char_dat; + + map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. + if (map_id >= 0) + map_fd = server[map_id].fd; + //Char should just had been saved before this packet, so this should be safe. [Skotlex] + char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); + if (char_data == NULL) { //Really shouldn't happen. + mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); + char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); + } + + if (runflag == CHARSERVER_ST_RUNNING && + session_isActive(map_fd) && + char_data) { + //Send the map server the auth of this player. + struct auth_node *node; + + //Update the "last map" as this is where the player must be spawned on the new map server. + char_data->last_point.map = RFIFOW(fd,18); + char_data->last_point.x = RFIFOW(fd,20); + char_data->last_point.y = RFIFOW(fd,22); + char_data->sex = RFIFOB(fd,30); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = RFIFOL(fd,2); + node->char_id = RFIFOL(fd,14); + node->login_id1 = RFIFOL(fd,6); + node->login_id2 = RFIFOL(fd,10); + node->sex = RFIFOB(fd,30); + node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) + node->ip = ntohl(RFIFOL(fd,31)); + node->group_id = RFIFOL(fd,35); + node->changing_mapservers = 1; + idb_put(auth_db, RFIFOL(fd,2), node); + + data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); + data->char_id = char_data->char_id; + data->server = map_id; //Update server where char is. + + //Reply with an ack. + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOSET(fd,30); + } else { //Reply with nak + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOL(fd,6) = 0; //Set login1 to 0. + WFIFOSET(fd,30); + } + RFIFOSKIP(fd,39); + } + break; + + case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] + if (RFIFOREST(fd) < 10) + return 0; + { + int char_id, friend_id; + char_id = RFIFOL(fd,2); + friend_id = RFIFOL(fd,6); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", + friend_db, char_id, friend_id)) { + Sql_ShowDebug(sql_handle); + break; + } + RFIFOSKIP(fd,10); + } + break; + + case 0x2b08: // char name request + if (RFIFOREST(fd) < 6) + return 0; + + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b09; + WFIFOL(fd,2) = RFIFOL(fd,2); + char_loadName((int)RFIFOL(fd,2), (char *)WFIFOP(fd,6)); + WFIFOSET(fd,30); + + RFIFOSKIP(fd,6); + break; + + case 0x2b0c: // Map server send information to change an email of an account -> login-server + if (RFIFOREST(fd) < 86) + return 0; + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,86); + memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B + WFIFOW(login_fd,0) = 0x2722; + WFIFOSET(login_fd,86); + } + RFIFOSKIP(fd, 86); + break; + + case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + if (RFIFOREST(fd) < 44) + return 0; + { + int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline + char esc_name[NAME_LENGTH*2+1]; + + int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) + const char *name = (char *)RFIFOP(fd,6); // name of the target character + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban + short year = RFIFOW(fd,32); + short month = RFIFOW(fd,34); + short day = RFIFOW(fd,36); + short hour = RFIFOW(fd,38); + short minute = RFIFOW(fd,40); + short second = RFIFOW(fd,42); + RFIFOSKIP(fd,44); + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) == 0) { + result = 1; // 1-player not found + } else if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + Sql_ShowDebug(sql_handle); + //FIXME: set proper result value? + else { + char name[NAME_LENGTH]; + int account_id; + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + + if (login_fd <= 0) + result = 3; // 3-login-server offline + //FIXME: need to move this check to login server [ultramage] + // else + // if( acc != -1 && isGM(acc) < isGM(account_id) ) + // result = 2; // 2-gm level too low + else + switch (type) { + case 1: // block + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 5; // new account status + WFIFOSET(login_fd,10); + break; + case 2: // ban + WFIFOHEAD(login_fd,18); + WFIFOW(login_fd, 0) = 0x2725; + WFIFOL(login_fd, 2) = account_id; + WFIFOW(login_fd, 6) = year; + WFIFOW(login_fd, 8) = month; + WFIFOW(login_fd,10) = day; + WFIFOW(login_fd,12) = hour; + WFIFOW(login_fd,14) = minute; + WFIFOW(login_fd,16) = second; + WFIFOSET(login_fd,18); + break; + case 3: // unblock + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 0; // new account status + WFIFOSET(login_fd,10); + break; + case 4: // unban + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272a; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 5: // changesex + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2727; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + } + } + + Sql_FreeResult(sql_handle); + + // send answer if a player ask, not if the server ask + if (acc != -1 && type != 5) { // Don't send answer for changesex + WFIFOHEAD(fd,34); + WFIFOW(fd, 0) = 0x2b0f; + WFIFOL(fd, 2) = acc; + safestrncpy((char *)WFIFOP(fd,6), name, NAME_LENGTH); + WFIFOW(fd,30) = type; + WFIFOW(fd,32) = result; + WFIFOSET(fd,34); + } + } + break; + + case 0x2b10: // Update and send fame ranking list + if (RFIFOREST(fd) < 11) + return 0; + { + int cid = RFIFOL(fd, 2); + int fame = RFIFOL(fd, 6); + char type = RFIFOB(fd, 10); + int size; + struct fame_list *list; + int player_pos; + int fame_pos; + + switch (type) { + case 1: + size = fame_list_size_smith; + list = smith_fame_list; + break; + case 2: + size = fame_list_size_chemist; + list = chemist_fame_list; + break; + case 3: + size = fame_list_size_taekwon; + list = taekwon_fame_list; + break; + default: + size = 0; + list = NULL; + break; + } + + ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player + ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be + + if (player_pos == size && fame_pos == size) + ;// not on list and not enough fame to get on it + else if (fame_pos == player_pos) { + // same position + list[player_pos].fame = fame; + char_update_fame_list(type, player_pos, fame); + } else { + // move in the list + if (player_pos == size) { + // new ranker - not in the list + ARR_MOVE(size - 1, fame_pos, list, struct fame_list); + list[fame_pos].id = cid; + list[fame_pos].fame = fame; + char_loadName(cid, list[fame_pos].name); + } else { + // already in the list + if (fame_pos == size) + --fame_pos;// move to the end of the list + ARR_MOVE(player_pos, fame_pos, list, struct fame_list); + list[fame_pos].fame = fame; + } + char_send_fame_list(-1); + } + + RFIFOSKIP(fd,11); + } + break; + + // Divorce chars + case 0x2b11: + if (RFIFOREST(fd) < 10) + return 0; + + divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b16: // Receive rates [Wizputer] + if (RFIFOREST(fd) < 14) + return 0; + { + char esc_server_name[sizeof(server_name)*2+1]; + + Sql_EscapeString(sql_handle, esc_server_name, server_name); + + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", + ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10))) + Sql_ShowDebug(sql_handle); + RFIFOSKIP(fd,14); + } + break; + + case 0x2b17: // Character disconnected set online 0 [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b18: // Reset all chars to offline [Wizputer] + set_all_offline(id); + RFIFOSKIP(fd,2); + break; + + case 0x2b19: // Character set online [Wizputer] + if (RFIFOREST(fd) < 10) + return 0; + set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b1a: // Build and send fame ranking lists [DracoRPG] + if (RFIFOREST(fd) < 2) + return 0; + char_read_fame_list(); + char_send_fame_list(-1); + RFIFOSKIP(fd,2); + break; + + case 0x2b1c: //Request to save status change data. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { #ifdef ENABLE_SC_SAVING - int count, aid, cid; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - if( count > 0 ) - { - struct status_change_data data; - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); - for( i = 0; i < count; ++i ) - { - memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); - if( i > 0 ) - StringBuf_AppendStr(&buf, ", "); - StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, - data.type, data.tick, data.val1, data.val2, data.val3, data.val4); - } - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } + int count, aid, cid; + + aid = RFIFOL(fd, 4); + cid = RFIFOL(fd, 8); + count = RFIFOW(fd, 12); + + if (count > 0) { + struct status_change_data data; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); + for (i = 0; i < count; ++i) { + memcpy(&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); + if (i > 0) + StringBuf_AppendStr(&buf, ", "); + StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, + data.type, data.tick, data.val1, data.val2, data.val3, data.val4); + } + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } #endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 19) - return 0; - - { - int account_id; - int char_id; - int login_id1; - char sex; - uint32 ip; - struct auth_node* node; - struct mmo_charstatus* cd; - struct mmo_charstatus char_dat; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - login_id1 = RFIFOL(fd,10); - sex = RFIFOB(fd,14); - ip = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - node = (struct auth_node*)idb_get(auth_db, account_id); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - if( cd == NULL ) - { //Really shouldn't happen. - mmo_char_fromsql(char_id, &char_dat, true); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - } - if( runflag == CHARSERVER_ST_RUNNING && - cd != NULL && - node != NULL && - node->account_id == account_id && - node->char_id == char_id && - node->login_id1 == login_id1 && - node->sex == sex /*&& - node->ip == ip*/ ) - {// auth ok - cd->sex = sex; - - WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); - WFIFOW(fd,0) = 0x2afd; - WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = node->login_id1; - WFIFOL(fd,12) = node->login_id2; - WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" - WFIFOL(fd,20) = node->group_id; - WFIFOB(fd,24) = node->changing_mapservers; - memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(fd, WFIFOW(fd,2)); - - // only use the auth once and mark user online - idb_remove(auth_db, account_id); - set_char_online(id, char_id, account_id); - } - else - {// auth failed - WFIFOHEAD(fd,19); - WFIFOW(fd,0) = 0x2b27; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - WFIFOL(fd,10) = login_id1; - WFIFOB(fd,14) = sex; - WFIFOL(fd,15) = htonl(ip); - WFIFOSET(fd,19); - } - } - break; - - case 0x2736: // ip address update - if (RFIFOREST(fd) < 6) return 0; - server[id].ip = ntohl(RFIFOL(fd, 2)); - ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x3008: - if( RFIFOREST(fd) < RFIFOW(fd,4) ) - return 0;/* packet wasn't fully received yet (still fragmented) */ - else { - int sfd;/* stat server fd */ - RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ - - if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true) ) == -1 ) { - RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ - break;/* connection not possible, we drop the report */ - } - - session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ - - WFIFOHEAD(sfd, RFIFOW(fd,2) ); - - memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2)); - - WFIFOSET(sfd, RFIFOW(fd,2) ); - - flush_fifo(sfd); - - do_close(sfd); - - RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ - } - break; - - - default: - { - // inter server - packet - int r = inter_parse_frommap(fd); - if (r == 1) break; // processed - if (r == 2) return 0; // need more packet - - // no inter server packet. no char server packet -> disconnect - ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } // switch - } // while - - return 0; + RFIFOSKIP(fd, RFIFOW(fd, 2)); + } + break; + + case 0x2b23: // map-server alive packet + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2b24; + WFIFOSET(fd,2); + RFIFOSKIP(fd,2); + break; + + case 0x2b26: // auth request from map-server + if (RFIFOREST(fd) < 19) + return 0; + + { + int account_id; + int char_id; + int login_id1; + char sex; + uint32 ip; + struct auth_node *node; + struct mmo_charstatus *cd; + struct mmo_charstatus char_dat; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + login_id1 = RFIFOL(fd,10); + sex = RFIFOB(fd,14); + ip = ntohl(RFIFOL(fd,15)); + RFIFOSKIP(fd,19); + + node = (struct auth_node *)idb_get(auth_db, account_id); + cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); + if (cd == NULL) { + //Really shouldn't happen. + mmo_char_fromsql(char_id, &char_dat, true); + cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); + } + if (runflag == CHARSERVER_ST_RUNNING && + cd != NULL && + node != NULL && + node->account_id == account_id && + node->char_id == char_id && + node->login_id1 == login_id1 && + node->sex == sex /*&& + node->ip == ip*/) { + // auth ok + cd->sex = sex; + + WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); + WFIFOW(fd,0) = 0x2afd; + WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = node->login_id1; + WFIFOL(fd,12) = node->login_id2; + WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" + WFIFOL(fd,20) = node->group_id; + WFIFOB(fd,24) = node->changing_mapservers; + memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); + WFIFOSET(fd, WFIFOW(fd,2)); + + // only use the auth once and mark user online + idb_remove(auth_db, account_id); + set_char_online(id, char_id, account_id); + } else { + // auth failed + WFIFOHEAD(fd,19); + WFIFOW(fd,0) = 0x2b27; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = char_id; + WFIFOL(fd,10) = login_id1; + WFIFOB(fd,14) = sex; + WFIFOL(fd,15) = htonl(ip); + WFIFOSET(fd,19); + } + } + break; + + case 0x2736: // ip address update + if (RFIFOREST(fd) < 6) return 0; + server[id].ip = ntohl(RFIFOL(fd, 2)); + ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x3008: + if (RFIFOREST(fd) < RFIFOW(fd,4)) + return 0;/* packet wasn't fully received yet (still fragmented) */ + else { + int sfd;/* stat server fd */ + RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ + + if ((sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true)) == -1) { + RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ + break;/* connection not possible, we drop the report */ + } + + session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ + + WFIFOHEAD(sfd, RFIFOW(fd,2)); + + memcpy((char *)WFIFOP(sfd,0), (char *)RFIFOP(fd, 0), RFIFOW(fd,2)); + + WFIFOSET(sfd, RFIFOW(fd,2)); + + flush_fifo(sfd); + + do_close(sfd); + + RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ + } + break; + + + default: { + // inter server - packet + int r = inter_parse_frommap(fd); + if (r == 1) break; // processed + if (r == 2) return 0; // need more packet + + // no inter server packet. no char server packet -> disconnect + ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); + set_eof(fd); + return 0; + } + } // switch + } // while + + return 0; } void do_init_mapif(void) { - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_init(i); + int i; + for (i = 0; i < ARRAYLENGTH(server); ++i) + mapif_server_init(i); } void do_final_mapif(void) { - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_destroy(i); + int i; + for (i = 0; i < ARRAYLENGTH(server); ++i) + mapif_server_destroy(i); } // Searches for the mapserver that has a given map (and optionally ip/port, if not -1). // If found, returns the server's index in the 'server' array (otherwise returns -1). int search_mapserver(unsigned short map, uint32 ip, uint16 port) { - int i, j; - - for(i = 0; i < ARRAYLENGTH(server); i++) - { - if (server[i].fd > 0 - && (ip == (uint32)-1 || server[i].ip == ip) - && (port == (uint16)-1 || server[i].port == port)) - { - for (j = 0; server[i].map[j]; j++) - if (server[i].map[j] == map) - return i; - } - } - - return -1; + int i, j; + + for (i = 0; i < ARRAYLENGTH(server); i++) { + if (server[i].fd > 0 + && (ip == (uint32)-1 || server[i].ip == ip) + && (port == (uint16)-1 || server[i].port == port)) { + for (j = 0; server[i].map[j]; j++) + if (server[i].map[j] == map) + return i; + } + } + + return -1; } // Initialization process (currently only initialization inter_mapif) static int char_mapif_init(int fd) { - return inter_mapif_init(fd); + return inter_mapif_init(fd); } //-------------------------------------------- @@ -3377,15 +3321,15 @@ static int char_mapif_init(int fd) //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - if( i < subnet_count ) { - ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); - return subnet[i].map_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } + int i; + ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); + if (i < subnet_count) { + ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); + return subnet[i].map_ip; + } else { + ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); + return 0; + } } @@ -3397,13 +3341,14 @@ int lan_subnetcheck(uint32 ip) /// 5 (0x71b): To delete a character you must withdraw from the party. /// Any (0x718): An unknown error has occurred. void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) -{// HC: <0828>.W .L .L .L - WFIFOHEAD(fd,14); - WFIFOW(fd,0) = 0x828; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOL(fd,10) = TOL(delete_date); - WFIFOSET(fd,14); +{ + // HC: <0828>.W .L .L .L + WFIFOHEAD(fd,14); + WFIFOW(fd,0) = 0x828; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOL(fd,10) = TOL(delete_date); + WFIFOSET(fd,14); } @@ -3416,12 +3361,13 @@ void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) /// 5 (0x71e): Date of birth do not match. /// Any (0x718): An unknown error has occurred. void char_delete2_accept_ack(int fd, int char_id, uint32 result) -{// HC: <082a>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82a; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{ + // HC: <082a>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82a; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } @@ -3430,804 +3376,797 @@ void char_delete2_accept_ack(int fd, int char_id, uint32 result) /// 2 (0x719): A database error occurred. /// Any (0x718): An unknown error has occurred. void char_delete2_cancel_ack(int fd, int char_id, uint32 result) -{// HC: <082c>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{ + // HC: <082c>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } -static void char_delete2_req(int fd, struct char_session_data* sd) -{// CH: <0827>.W .L - int char_id, i; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( delete_date ) {// character already queued for deletion - char_delete2_ack(fd, char_id, 0, 0); - return; - } - -/* - // Aegis imposes these checks probably to avoid dead member - // entries in guilds/parties, otherwise they are not required. - // TODO: Figure out how these are enforced during waiting. - if( guild_id ) - {// character in guild - char_delete2_ack(fd, char_id, 4, 0); - return; - } - - if( party_id ) - {// character in party - char_delete2_ack(fd, char_id, 5, 0); - return; - } -*/ - - // success - delete_date = time(NULL)+char_del_delay; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - char_delete2_ack(fd, char_id, 1, delete_date); +static void char_delete2_req(int fd, struct char_session_data *sd) +{ + // CH: <0827>.W .L + int char_id, i; + char *data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + delete_date = strtoul(data, NULL, 10); + + if (delete_date) { // character already queued for deletion + char_delete2_ack(fd, char_id, 0, 0); + return; + } + + /* + // Aegis imposes these checks probably to avoid dead member + // entries in guilds/parties, otherwise they are not required. + // TODO: Figure out how these are enforced during waiting. + if( guild_id ) + {// character in guild + char_delete2_ack(fd, char_id, 4, 0); + return; + } + + if( party_id ) + {// character in party + char_delete2_ack(fd, char_id, 5, 0); + return; + } + */ + + // success + delete_date = time(NULL)+char_del_delay; + + if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id)) { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + char_delete2_ack(fd, char_id, 1, delete_date); } -static void char_delete2_accept(int fd, struct char_session_data* sd) -{// CH: <0829>.W .L .6B - char birthdate[8+1]; - int char_id, i, k; - unsigned int base_level; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); - - // construct "YY-MM-DD" - birthdate[0] = RFIFOB(fd,6); - birthdate[1] = RFIFOB(fd,7); - birthdate[2] = '-'; - birthdate[3] = RFIFOB(fd,8); - birthdate[4] = RFIFOB(fd,9); - birthdate[5] = '-'; - birthdate[6] = RFIFOB(fd,10); - birthdate[7] = RFIFOB(fd,11); - birthdate[8] = 0; - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// data error - Sql_ShowDebug(sql_handle); - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( !delete_date || delete_date>time(NULL) ) - {// not queued or delay not yet passed - char_delete2_accept_ack(fd, char_id, 4); - return; - } - - if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century - {// birth date is wrong - char_delete2_accept_ack(fd, char_id, 5); - return; - } - - if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) ) - {// character level config restriction - char_delete2_accept_ack(fd, char_id, 2); - return; - } - - // success - if( delete_char_sql(char_id) < 0 ) - { - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - // refresh character list cache - for(k = i; k < MAX_CHARS-1; k++) - { - sd->found_char[k] = sd->found_char[k+1]; - } - sd->found_char[MAX_CHARS-1] = -1; - - char_delete2_accept_ack(fd, char_id, 1); +static void char_delete2_accept(int fd, struct char_session_data *sd) +{ + // CH: <0829>.W .L .6B + char birthdate[8+1]; + int char_id, i, k; + unsigned int base_level; + char *data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); + + // construct "YY-MM-DD" + birthdate[0] = RFIFOB(fd,6); + birthdate[1] = RFIFOB(fd,7); + birthdate[2] = '-'; + birthdate[3] = RFIFOB(fd,8); + birthdate[4] = RFIFOB(fd,9); + birthdate[5] = '-'; + birthdate[6] = RFIFOB(fd,10); + birthdate[7] = RFIFOB(fd,11); + birthdate[8] = 0; + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // data error + Sql_ShowDebug(sql_handle); + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + base_level = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 1, &data, NULL); + delete_date = strtoul(data, NULL, 10); + + if (!delete_date || delete_date>time(NULL)) { + // not queued or delay not yet passed + char_delete2_accept_ack(fd, char_id, 4); + return; + } + + if (strcmp(sd->birthdate+2, birthdate)) { // +2 to cut off the century + // birth date is wrong + char_delete2_accept_ack(fd, char_id, 5); + return; + } + + if ((char_del_level > 0 && base_level >= (unsigned int)char_del_level) || (char_del_level < 0 && base_level <= (unsigned int)(-char_del_level))) { + // character level config restriction + char_delete2_accept_ack(fd, char_id, 2); + return; + } + + // success + if (delete_char_sql(char_id) < 0) { + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + // refresh character list cache + for (k = i; k < MAX_CHARS-1; k++) { + sd->found_char[k] = sd->found_char[k+1]; + } + sd->found_char[MAX_CHARS-1] = -1; + + char_delete2_accept_ack(fd, char_id, 1); } -static void char_delete2_cancel(int fd, struct char_session_data* sd) -{// CH: <082b>.W .L - int char_id, i; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - // there is no need to check, whether or not the character was - // queued for deletion, as the client prints an error message by - // itself, if it was not the case (@see char_delete2_cancel_ack) - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - char_delete2_cancel_ack(fd, char_id, 1); +static void char_delete2_cancel(int fd, struct char_session_data *sd) +{ + // CH: <082b>.W .L + int char_id, i; + + char_id = RFIFOL(fd,2); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + // there is no need to check, whether or not the character was + // queued for deletion, as the client prints an error message by + // itself, if it was not the case (@see char_delete2_cancel_ack) + if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + char_delete2_cancel_ack(fd, char_id, 1); } int parse_char(int fd) { - int i, ch; - char email[40]; - unsigned short cmd; - int map_fd; - struct char_session_data* sd; - uint32 ipl = session[fd]->client_addr; - - sd = (struct char_session_data*)session[fd]->session_data; - - // disconnect any player if no login-server. - if(login_fd < 0) - set_eof(fd); - - if(session[fd]->flag.eof) - { - if( sd != NULL && sd->auth ) - { // already authed client - struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); - if( data != NULL && data->fd == fd) - data->fd = -1; - if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - } - do_close(fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - //For use in packets that depend on an sd being present [Skotlex] - #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } - - cmd = RFIFOW(fd,0); - switch( cmd ) - { - - // request to connect - // 0065 .L .L .L .W .B - case 0x65: - if( RFIFOREST(fd) < 17 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - int sex = RFIFOB(fd,16); - RFIFOSKIP(fd,17); - - ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); - - if (sd) { - //Received again auth packet for already authentified account?? Discard it. - //TODO: Perhaps log this as a hack attempt? - //TODO: and perhaps send back a reply? - break; - } - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data*)session[fd]->session_data; - sd->account_id = account_id; - sd->login_id1 = login_id1; - sd->login_id2 = login_id2; - sd->sex = sex; - sd->auth = false; // not authed yet - - // send back account_id - WFIFOHEAD(fd,4); - WFIFOL(fd,0) = account_id; - WFIFOSET(fd,4); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0;// rejected from server - WFIFOSET(fd,3); - break; - } - - // search authentification - node = (struct auth_node*)idb_get(auth_db, account_id); - if( node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 /*&& - node->ip == ipl*/ ) - {// authentication found (coming from map server) - idb_remove(auth_db, account_id); - char_auth_ok(fd, sd); - } - else - {// authentication not found (coming from login server) - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,23); - WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_fd,2) = sd->account_id; - WFIFOL(login_fd,6) = sd->login_id1; - WFIFOL(login_fd,10) = sd->login_id2; - WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(ipl); - WFIFOL(login_fd,19) = fd; - WFIFOSET(login_fd,23); - } else { // if no login-server, we must refuse connection - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - } - } - break; - - // char select - case 0x66: - FIFOSD_CHECK(3); - { - struct mmo_charstatus char_dat; - struct mmo_charstatus *cd; - char* data; - int char_id; - uint32 subnet_map_ip; - struct auth_node* node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) - || SQL_SUCCESS != Sql_NextRow(sql_handle) - || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) - { //Not found?? May be forged packet. - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; // rejected from server - WFIFOSET(fd,3); - break; - } - - char_id = atoi(data); - Sql_FreeResult(sql_handle); - mmo_char_fromsql(char_id, &char_dat, true); - - //Have to switch over to the DB instance otherwise data won't propagate [Kevin] - cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); - cd->sex = sd->sex; - - if (log_char) { - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", - charlog_db, sd->account_id, slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); - - // searching map server - i = search_mapserver(cd->last_point.map, -1, -1); - - // if map is not found, we check major cities - if (i < 0 || !cd->last_point.map) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] ); - if (j == ARRAYLENGTH(server)) { - ShowInfo("Connection Closed. No map servers available.\n"); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { - cd->last_point.x = 273; - cd->last_point.y = 354; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { - cd->last_point.x = 120; - cd->last_point.y = 100; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { - cd->last_point.x = 160; - cd->last_point.y = 94; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { - cd->last_point.x = 116; - cd->last_point.y = 57; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { - cd->last_point.x = 87; - cd->last_point.y = 117; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { - cd->last_point.x = 94; - cd->last_point.y = 103; - } else { - ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); - cd->last_point.map = j; - } - - //Send NEW auth packet [Kevin] - //FIXME: is this case even possible? [ultramage] - if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) - { - ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); - server[i].fd = -1; - memset(&server[i], 0, sizeof(struct mmo_map_server)); - //Send server closed. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = cd->char_id; - mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); - subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->char_id = cd->char_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->expiration_time = sd->expiration_time; - node->group_id = sd->group_id; - node->ip = ipl; - idb_put(auth_db, sd->account_id, node); - - set_char_online(-2,node->char_id,sd->account_id); - - } - break; - - // create new char + int i, ch; + char email[40]; + unsigned short cmd; + int map_fd; + struct char_session_data *sd; + uint32 ipl = session[fd]->client_addr; + + sd = (struct char_session_data *)session[fd]->session_data; + + // disconnect any player if no login-server. + if (login_fd < 0) + set_eof(fd); + + if (session[fd]->flag.eof) { + if (sd != NULL && sd->auth) { + // already authed client + struct online_char_data *data = (struct online_char_data *)idb_get(online_char_db, sd->account_id); + if (data != NULL && data->fd == fd) + data->fd = -1; + if (data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] + set_char_offline(-1,sd->account_id); + } + do_close(fd); + return 0; + } + + while (RFIFOREST(fd) >= 2) { + //For use in packets that depend on an sd being present [Skotlex] +#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } + + cmd = RFIFOW(fd,0); + switch (cmd) { + + // request to connect + // 0065 .L .L .L .W .B + case 0x65: + if (RFIFOREST(fd) < 17) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + int sex = RFIFOB(fd,16); + RFIFOSKIP(fd,17); + + ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); + + if (sd) { + //Received again auth packet for already authentified account?? Discard it. + //TODO: Perhaps log this as a hack attempt? + //TODO: and perhaps send back a reply? + break; + } + + CREATE(session[fd]->session_data, struct char_session_data, 1); + sd = (struct char_session_data *)session[fd]->session_data; + sd->account_id = account_id; + sd->login_id1 = login_id1; + sd->login_id2 = login_id2; + sd->sex = sex; + sd->auth = false; // not authed yet + + // send back account_id + WFIFOHEAD(fd,4); + WFIFOL(fd,0) = account_id; + WFIFOSET(fd,4); + + if (runflag != CHARSERVER_ST_RUNNING) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0;// rejected from server + WFIFOSET(fd,3); + break; + } + + // search authentification + node = (struct auth_node *)idb_get(auth_db, account_id); + if (node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 /*&& + node->ip == ipl*/) { + // authentication found (coming from map server) + idb_remove(auth_db, account_id); + char_auth_ok(fd, sd); + } else { + // authentication not found (coming from login server) + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,23); + WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account + WFIFOL(login_fd,2) = sd->account_id; + WFIFOL(login_fd,6) = sd->login_id1; + WFIFOL(login_fd,10) = sd->login_id2; + WFIFOB(login_fd,14) = sd->sex; + WFIFOL(login_fd,15) = htonl(ipl); + WFIFOL(login_fd,19) = fd; + WFIFOSET(login_fd,23); + } else { // if no login-server, we must refuse connection + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } + } + } + break; + + // char select + case 0x66: + FIFOSD_CHECK(3); + { + struct mmo_charstatus char_dat; + struct mmo_charstatus *cd; + char *data; + int char_id; + uint32 subnet_map_ip; + struct auth_node *node; + + int slot = RFIFOB(fd,2); + RFIFOSKIP(fd,3); + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) + || SQL_SUCCESS != Sql_NextRow(sql_handle) + || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL)) { + //Not found?? May be forged packet. + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); + break; + } + + char_id = atoi(data); + Sql_FreeResult(sql_handle); + mmo_char_fromsql(char_id, &char_dat, true); + + //Have to switch over to the DB instance otherwise data won't propagate [Kevin] + cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); + cd->sex = sd->sex; + + if (log_char) { + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", + charlog_db, sd->account_id, slot, esc_name)) + Sql_ShowDebug(sql_handle); + } + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); + + // searching map server + i = search_mapserver(cd->last_point.map, -1, -1); + + // if map is not found, we check major cities + if (i < 0 || !cd->last_point.map) { + unsigned short j; + //First check that there's actually a map server online. + ARR_FIND(0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0]); + if (j == ARRAYLENGTH(server)) { + ShowInfo("Connection Closed. No map servers available.\n"); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { + cd->last_point.x = 273; + cd->last_point.y = 354; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { + cd->last_point.x = 120; + cd->last_point.y = 100; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { + cd->last_point.x = 160; + cd->last_point.y = 94; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { + cd->last_point.x = 116; + cd->last_point.y = 57; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { + cd->last_point.x = 87; + cd->last_point.y = 117; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { + cd->last_point.x = 94; + cd->last_point.y = 103; + } else { + ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); + cd->last_point.map = j; + } + + //Send NEW auth packet [Kevin] + //FIXME: is this case even possible? [ultramage] + if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) { + ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); + server[i].fd = -1; + memset(&server[i], 0, sizeof(struct mmo_map_server)); + //Send server closed. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + + //Send player to map + WFIFOHEAD(fd,28); + WFIFOW(fd,0) = 0x71; + WFIFOL(fd,2) = cd->char_id; + mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char *)WFIFOP(fd,6)); + subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] + WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); + WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + WFIFOSET(fd,28); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->char_id = cd->char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->expiration_time = sd->expiration_time; + node->group_id = sd->group_id; + node->ip = ipl; + idb_put(auth_db, sd->account_id, node); + + set_char_online(-2,node->char_id,sd->account_id); + + } + break; + + // create new char #if PACKETVER >= 20120307 - // S 0970 .24B .B .W .W - case 0x970: - FIFOSD_CHECK(31); + // S 0970 .24B .B .W .W + case 0x970: + FIFOSD_CHECK(31); #else - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); + // S 0067 .24B .B .B .B .B .B .B .B .W .W + case 0x67: + FIFOSD_CHECK(37); #endif - if( !char_new ) //turn character creation on/off [Kevin] - i = -2; - else + if (!char_new) //turn character creation on/off [Kevin] + i = -2; + else #if PACKETVER >= 20120307 - i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); + i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); #else - i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); + i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); #endif - //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) - if (i < 0) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6e; - switch (i) { - case -1: WFIFOB(fd,2) = 0x00; break; - case -2: WFIFOB(fd,2) = 0xFF; break; - case -3: WFIFOB(fd,2) = 0x01; break; - } - WFIFOSET(fd,3); - } - else - { - int len; - // retrieve data - struct mmo_charstatus char_dat; - mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. - - // send to player - WFIFOHEAD(fd,2+MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); - WFIFOSET(fd,len); - - // add new entry to the chars list - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); - if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // the char_id of the new char - } + //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) + if (i < 0) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6e; + switch (i) { + case -1: + WFIFOB(fd,2) = 0x00; + break; + case -2: + WFIFOB(fd,2) = 0xFF; + break; + case -3: + WFIFOB(fd,2) = 0x01; + break; + } + WFIFOSET(fd,3); + } else { + int len; + // retrieve data + struct mmo_charstatus char_dat; + mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. + + // send to player + WFIFOHEAD(fd,2+MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6d; + len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); + WFIFOSET(fd,len); + + // add new entry to the chars list + ARR_FIND(0, MAX_CHARS, ch, sd->found_char[ch] == -1); + if (ch < MAX_CHARS) + sd->found_char[ch] = i; // the char_id of the new char + } #if PACKETVER >= 20120307 - RFIFOSKIP(fd,31); + RFIFOSKIP(fd,31); #else - RFIFOSKIP(fd,37); + RFIFOSKIP(fd,37); #endif - break; - - // delete char - case 0x68: - // 2004-04-19aSakexe+ langtype 12 char deletion packet - case 0x1fb: - if (cmd == 0x68) FIFOSD_CHECK(46); - if (cmd == 0x1fb) FIFOSD_CHECK(56); - { - int cid = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); - - // Check if e-mail is correct - if(strcmpi(email, sd->email) && //email does not matches and - ( - strcmp("a@a.com", sd->email) || //it is not default email, or - (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default - )) { //Fail - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - - // check if this char exists - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - { // Such a character does not exist in the account - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - break; - } - - // remove char from list and compact it - for(ch = i; ch < MAX_CHARS-1; ch++) - sd->found_char[ch] = sd->found_char[ch+1]; - sd->found_char[MAX_CHARS-1] = -1; - - /* Delete character */ - if(delete_char_sql(cid)<0){ - //can't delete the char - //either SQL error or can't delete by some CONFIG conditions - //del fail - WFIFOHEAD(fd,3); - WFIFOW(fd, 0) = 0x70; - WFIFOB(fd, 2) = 0; - WFIFOSET(fd, 3); - break; - } - /* Char successfully deleted.*/ - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x6f; - WFIFOSET(fd,2); - } - break; - - // client keep-alive packet (every 12 seconds) - // R 0187 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - - // char rename request - // R 028d .l .l .24B - case 0x28d: - FIFOSD_CHECK(34); - { - int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); - RFIFOSKIP(fd,34); - - if( aid != sd->account_id ) - break; - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( !check_char_name(name,esc_name) ) - { - i = 1; - safestrncpy(sd->new_name, name, NAME_LENGTH); - } - else - i = 0; - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x28e; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - //Confirm change name. - // 0x28f .L - case 0x28f: - // 0: Sucessfull - // 1: This character's name has already been changed. You cannot change a character's name more than once. - // 2: User information is not correct. - // 3: You have failed to change this character's name. - // 4: Another user is using this character name, so please select another one. - FIFOSD_CHECK(6); - { - int i; - int cid = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - i = rename_char_sql(sd, cid); - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x290; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - - // captcha code request (not implemented) - // R 07e5 .w .l - case 0x7e5: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,8); - break; - - // captcha code check (not implemented) - // R 07e7 .w .l .b10 .b14 - case 0x7e7: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,32); - break; - - // deletion timer request - case 0x827: - FIFOSD_CHECK(6); - char_delete2_req(fd, sd); - RFIFOSKIP(fd,6); - break; - - // deletion accept request - case 0x829: - FIFOSD_CHECK(12); - char_delete2_accept(fd, sd); - RFIFOSKIP(fd,12); - break; - - // deletion cancel request - case 0x82b: - FIFOSD_CHECK(6); - char_delete2_cancel(fd, sd); - RFIFOSKIP(fd,6); - break; - - // login as map-server - case 0x2af8: - if (RFIFOREST(fd) < 60) - return 0; - { - char* l_user = (char*)RFIFOP(fd,2); - char* l_pass = (char*)RFIFOP(fd,26); - l_user[23] = '\0'; - l_pass[23] = '\0'; - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 ); - if( runflag != CHARSERVER_ST_RUNNING || - i == ARRAYLENGTH(server) || - strcmp(l_user, userid) != 0 || - strcmp(l_pass, passwd) != 0 ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - server[i].fd = fd; - server[i].ip = ntohl(RFIFOL(fd,54)); - server[i].port = ntohs(RFIFOW(fd,58)); - server[i].users = 0; - memset(server[i].map, 0, sizeof(server[i].map)); - session[fd]->func_parse = parse_frommap; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - char_mapif_init(fd); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // unknown packet received - default: - ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + break; + + // delete char + case 0x68: + // 2004-04-19aSakexe+ langtype 12 char deletion packet + case 0x1fb: + if (cmd == 0x68) FIFOSD_CHECK(46); + if (cmd == 0x1fb) FIFOSD_CHECK(56); + { + int cid = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); + memcpy(email, RFIFOP(fd,6), 40); + RFIFOSKIP(fd,(cmd == 0x68) ? 46 : 56); + + // Check if e-mail is correct + if (strcmpi(email, sd->email) && //email does not matches and + ( + strcmp("a@a.com", sd->email) || //it is not default email, or + (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default + )) { //Fail + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + + // check if this char exists + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) { + // Such a character does not exist in the account + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + break; + } + + // remove char from list and compact it + for (ch = i; ch < MAX_CHARS-1; ch++) + sd->found_char[ch] = sd->found_char[ch+1]; + sd->found_char[MAX_CHARS-1] = -1; + + /* Delete character */ + if (delete_char_sql(cid)<0) { + //can't delete the char + //either SQL error or can't delete by some CONFIG conditions + //del fail + WFIFOHEAD(fd,3); + WFIFOW(fd, 0) = 0x70; + WFIFOB(fd, 2) = 0; + WFIFOSET(fd, 3); + break; + } + /* Char successfully deleted.*/ + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x6f; + WFIFOSET(fd,2); + } + break; + + // client keep-alive packet (every 12 seconds) + // R 0187 .l + case 0x187: + if (RFIFOREST(fd) < 6) + return 0; + RFIFOSKIP(fd,6); + break; + + // char rename request + // R 028d .l .l .24B + case 0x28d: + FIFOSD_CHECK(34); + { + int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); + RFIFOSKIP(fd,34); + + if (aid != sd->account_id) + break; + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) + break; + + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (!check_char_name(name,esc_name)) { + i = 1; + safestrncpy(sd->new_name, name, NAME_LENGTH); + } else + i = 0; + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x28e; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + //Confirm change name. + // 0x28f .L + case 0x28f: + // 0: Sucessfull + // 1: This character's name has already been changed. You cannot change a character's name more than once. + // 2: User information is not correct. + // 3: You have failed to change this character's name. + // 4: Another user is using this character name, so please select another one. + FIFOSD_CHECK(6); + { + int i; + int cid = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) + break; + i = rename_char_sql(sd, cid); + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x290; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + + // captcha code request (not implemented) + // R 07e5 .w .l + case 0x7e5: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,8); + break; + + // captcha code check (not implemented) + // R 07e7 .w .l .b10 .b14 + case 0x7e7: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,32); + break; + + // deletion timer request + case 0x827: + FIFOSD_CHECK(6); + char_delete2_req(fd, sd); + RFIFOSKIP(fd,6); + break; + + // deletion accept request + case 0x829: + FIFOSD_CHECK(12); + char_delete2_accept(fd, sd); + RFIFOSKIP(fd,12); + break; + + // deletion cancel request + case 0x82b: + FIFOSD_CHECK(6); + char_delete2_cancel(fd, sd); + RFIFOSKIP(fd,6); + break; + + // login as map-server + case 0x2af8: + if (RFIFOREST(fd) < 60) + return 0; + { + char *l_user = (char *)RFIFOP(fd,2); + char *l_pass = (char *)RFIFOP(fd,26); + l_user[23] = '\0'; + l_pass[23] = '\0'; + ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd <= 0); + if (runflag != CHARSERVER_ST_RUNNING || + i == ARRAYLENGTH(server) || + strcmp(l_user, userid) != 0 || + strcmp(l_pass, passwd) != 0) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } else { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + + server[i].fd = fd; + server[i].ip = ntohl(RFIFOL(fd,54)); + server[i].port = ntohs(RFIFOW(fd,58)); + server[i].users = 0; + memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + char_mapif_init(fd); + } + + RFIFOSKIP(fd,60); + } + return 0; // avoid processing of followup packets here + + // unknown packet received + default: + ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } // Console Command Parser [Wizputer] -int parse_console(const char* command) +int parse_console(const char *command) { - ShowNotice("Console command: %s\n", command); - - if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ) - { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) + runflag = 0; + else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if (strcmpi("help", command) == 0) { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + } + + return 0; } int mapif_sendall(unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0 && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_send(int fd, unsigned char *buf, unsigned int len) { - if (fd >= 0) { - int i; - ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd ); - if( i < ARRAYLENGTH(server) ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - return 0; + if (fd >= 0) { + int i; + ARR_FIND(0, ARRAYLENGTH(server), i, fd == server[i].fd); + if (i < ARRAYLENGTH(server)) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + return 1; + } + } + return 0; } int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[6]; - int users = count_users(); - - // only send an update when needed - static int prev_users = 0; - if( prev_users == users ) - return 0; - prev_users = users; - - if( login_fd > 0 && session[login_fd] ) - { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - - return 0; + uint8 buf[6]; + int users = count_users(); + + // only send an update when needed + static int prev_users = 0; + if (prev_users == users) + return 0; + prev_users = users; + + if (login_fd > 0 && session[login_fd]) { + // send number of user to login server + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2714; + WFIFOL(login_fd,2) = users; + WFIFOSET(login_fd,6); + } + + // send number of players to all map-servers + WBUFW(buf,0) = 0x2b00; + WBUFL(buf,2) = users; + mapif_sendall(buf,6); + + return 0; } /** @@ -4236,66 +4175,64 @@ int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) */ static int send_accounts_tologin_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = db_data2ptr(data); - int* i = va_arg(ap, int*); - - if(character->server > -1) - { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; + struct online_char_data *character = db_data2ptr(data); + int *i = va_arg(ap, int *); + + if (character->server > -1) { + WFIFOL(login_fd,8+(*i)*4) = character->account_id; + (*i)++; + return 1; + } + return 0; } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd]) - { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - return 0; + if (login_fd > 0 && session[login_fd]) { + // send account list to login server + int users = online_char_db->size(online_char_db); + int i = 0; + + WFIFOHEAD(login_fd,8+users*4); + WFIFOW(login_fd,0) = 0x272d; + online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); + WFIFOW(login_fd,2) = 8+ i*4; + WFIFOL(login_fd,4) = i; + WFIFOSET(login_fd,WFIFOW(login_fd,2)); + } + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd] != NULL) - return 0; - - ShowInfo("Attempt to connect to login-server...\n"); - login_fd = make_connection(login_ip, login_port, false); - if (login_fd == -1) - { //Try again later. [Skotlex] - login_fd = 0; - return 0; - } - session[login_fd]->func_parse = parse_fromlogin; - session[login_fd]->flag.server = 1; - realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - WFIFOHEAD(login_fd,86); - WFIFOW(login_fd,0) = 0x2710; - memcpy(WFIFOP(login_fd,2), userid, 24); - memcpy(WFIFOP(login_fd,26), passwd, 24); - WFIFOL(login_fd,50) = 0; - WFIFOL(login_fd,54) = htonl(char_ip); - WFIFOW(login_fd,58) = htons(char_port); - memcpy(WFIFOP(login_fd,60), server_name, 20); - WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; - WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] - WFIFOSET(login_fd,86); - - return 1; + if (login_fd > 0 && session[login_fd] != NULL) + return 0; + + ShowInfo("Attempt to connect to login-server...\n"); + login_fd = make_connection(login_ip, login_port, false); + if (login_fd == -1) { + //Try again later. [Skotlex] + login_fd = 0; + return 0; + } + session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->flag.server = 1; + realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + WFIFOHEAD(login_fd,86); + WFIFOW(login_fd,0) = 0x2710; + memcpy(WFIFOP(login_fd,2), userid, 24); + memcpy(WFIFOP(login_fd,26), passwd, 24); + WFIFOL(login_fd,50) = 0; + WFIFOL(login_fd,54) = htonl(char_ip); + WFIFOW(login_fd,58) = htons(char_port); + memcpy(WFIFOP(login_fd,60), server_name, 20); + WFIFOW(login_fd,80) = 0; + WFIFOW(login_fd,82) = char_maintenance; + WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] + WFIFOSET(login_fd,86); + + return 1; } //------------------------------------------------ @@ -4304,13 +4241,13 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data //------------------------------------------------ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) { - struct online_char_data* character; - if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) - { //Mark it offline due to timeout. - character->waiting_disconnect = INVALID_TIMER; - set_char_offline(character->char_id, character->account_id); - } - return 0; + struct online_char_data *character; + if ((character = (struct online_char_data *)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) { + //Mark it offline due to timeout. + character->waiting_disconnect = INVALID_TIMER; + set_char_offline(character->char_id, character->account_id); + } + return 0; } /** @@ -4318,21 +4255,21 @@ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_ */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character= db_data2ptr(data); - if (character->fd != -1) - return 0; //Character still connected - if (character->server == -2) //Unknown server.. set them offline - set_char_offline(character->char_id, character->account_id); - if (character->server < 0) - //Free data from players that have not been online for a while. - db_remove(online_char_db, key); - return 0; + struct online_char_data *character= db_data2ptr(data); + if (character->fd != -1) + return 0; //Character still connected + if (character->server == -2) //Unknown server.. set them offline + set_char_offline(character->char_id, character->account_id); + if (character->server < 0) + //Free data from players that have not been online for a while. + db_remove(online_char_db, key); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; + online_char_db->foreach(online_char_db, online_data_cleanup_sub); + return 0; } //---------------------------------- @@ -4341,327 +4278,323 @@ static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data //---------------------------------- int char_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - remove_control_chars(w1); - remove_control_chars(w2); - remove_control_chars(w3); - remove_control_chars(w4); - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if( subnet_count > 1 ) /* only useful if there is more than 1 */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if ((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + remove_control_chars(w1); + remove_control_chars(w2); + remove_control_chars(w3); + remove_control_chars(w4); + + if (strcmpi(w1, "subnet") == 0) { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if (subnet_count > 1) /* only useful if there is more than 1 */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } -void sql_config_read(const char* cfgName) +void sql_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("File not found: %s\n", cfgName); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if(!strcmpi(w1,"char_db")) - safestrncpy(char_db, w2, sizeof(char_db)); - else if(!strcmpi(w1,"scdata_db")) - safestrncpy(scdata_db, w2, sizeof(scdata_db)); - else if(!strcmpi(w1,"cart_db")) - safestrncpy(cart_db, w2, sizeof(cart_db)); - else if(!strcmpi(w1,"inventory_db")) - safestrncpy(inventory_db, w2, sizeof(inventory_db)); - else if(!strcmpi(w1,"charlog_db")) - safestrncpy(charlog_db, w2, sizeof(charlog_db)); - else if(!strcmpi(w1,"storage_db")) - safestrncpy(storage_db, w2, sizeof(storage_db)); - else if(!strcmpi(w1,"reg_db")) - safestrncpy(reg_db, w2, sizeof(reg_db)); - else if(!strcmpi(w1,"skill_db")) - safestrncpy(skill_db, w2, sizeof(skill_db)); - else if(!strcmpi(w1,"interlog_db")) - safestrncpy(interlog_db, w2, sizeof(interlog_db)); - else if(!strcmpi(w1,"memo_db")) - safestrncpy(memo_db, w2, sizeof(memo_db)); - else if(!strcmpi(w1,"guild_db")) - safestrncpy(guild_db, w2, sizeof(guild_db)); - else if(!strcmpi(w1,"guild_alliance_db")) - safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); - else if(!strcmpi(w1,"guild_castle_db")) - safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); - else if(!strcmpi(w1,"guild_expulsion_db")) - safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); - else if(!strcmpi(w1,"guild_member_db")) - safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); - else if(!strcmpi(w1,"guild_skill_db")) - safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); - else if(!strcmpi(w1,"guild_position_db")) - safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); - else if(!strcmpi(w1,"guild_storage_db")) - safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); - else if(!strcmpi(w1,"party_db")) - safestrncpy(party_db, w2, sizeof(party_db)); - else if(!strcmpi(w1,"pet_db")) - safestrncpy(pet_db, w2, sizeof(pet_db)); - else if(!strcmpi(w1,"mail_db")) - safestrncpy(mail_db, w2, sizeof(mail_db)); - else if(!strcmpi(w1,"auction_db")) - safestrncpy(auction_db, w2, sizeof(auction_db)); - else if(!strcmpi(w1,"friend_db")) - safestrncpy(friend_db, w2, sizeof(friend_db)); - else if(!strcmpi(w1,"hotkey_db")) - safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); - else if(!strcmpi(w1,"quest_db")) - safestrncpy(quest_db,w2,sizeof(quest_db)); - else if(!strcmpi(w1,"homunculus_db")) - safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); - else if(!strcmpi(w1,"skill_homunculus_db")) - safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); - else if(!strcmpi(w1,"mercenary_db")) - safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); - else if(!strcmpi(w1,"mercenary_owner_db")) - safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); - //support the import command, just like any other config - else if(!strcmpi(w1,"import")) - sql_config_read(w2); - } - fclose(fp); - ShowInfo("Done reading %s.\n", cfgName); + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("File not found: %s\n", cfgName); + return; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (!strcmpi(w1,"char_db")) + safestrncpy(char_db, w2, sizeof(char_db)); + else if (!strcmpi(w1,"scdata_db")) + safestrncpy(scdata_db, w2, sizeof(scdata_db)); + else if (!strcmpi(w1,"cart_db")) + safestrncpy(cart_db, w2, sizeof(cart_db)); + else if (!strcmpi(w1,"inventory_db")) + safestrncpy(inventory_db, w2, sizeof(inventory_db)); + else if (!strcmpi(w1,"charlog_db")) + safestrncpy(charlog_db, w2, sizeof(charlog_db)); + else if (!strcmpi(w1,"storage_db")) + safestrncpy(storage_db, w2, sizeof(storage_db)); + else if (!strcmpi(w1,"reg_db")) + safestrncpy(reg_db, w2, sizeof(reg_db)); + else if (!strcmpi(w1,"skill_db")) + safestrncpy(skill_db, w2, sizeof(skill_db)); + else if (!strcmpi(w1,"interlog_db")) + safestrncpy(interlog_db, w2, sizeof(interlog_db)); + else if (!strcmpi(w1,"memo_db")) + safestrncpy(memo_db, w2, sizeof(memo_db)); + else if (!strcmpi(w1,"guild_db")) + safestrncpy(guild_db, w2, sizeof(guild_db)); + else if (!strcmpi(w1,"guild_alliance_db")) + safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); + else if (!strcmpi(w1,"guild_castle_db")) + safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); + else if (!strcmpi(w1,"guild_expulsion_db")) + safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); + else if (!strcmpi(w1,"guild_member_db")) + safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); + else if (!strcmpi(w1,"guild_skill_db")) + safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); + else if (!strcmpi(w1,"guild_position_db")) + safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); + else if (!strcmpi(w1,"guild_storage_db")) + safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); + else if (!strcmpi(w1,"party_db")) + safestrncpy(party_db, w2, sizeof(party_db)); + else if (!strcmpi(w1,"pet_db")) + safestrncpy(pet_db, w2, sizeof(pet_db)); + else if (!strcmpi(w1,"mail_db")) + safestrncpy(mail_db, w2, sizeof(mail_db)); + else if (!strcmpi(w1,"auction_db")) + safestrncpy(auction_db, w2, sizeof(auction_db)); + else if (!strcmpi(w1,"friend_db")) + safestrncpy(friend_db, w2, sizeof(friend_db)); + else if (!strcmpi(w1,"hotkey_db")) + safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); + else if (!strcmpi(w1,"quest_db")) + safestrncpy(quest_db,w2,sizeof(quest_db)); + else if (!strcmpi(w1,"homunculus_db")) + safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); + else if (!strcmpi(w1,"skill_homunculus_db")) + safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); + else if (!strcmpi(w1,"mercenary_db")) + safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); + else if (!strcmpi(w1,"mercenary_owner_db")) + safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); + //support the import command, just like any other config + else if (!strcmpi(w1,"import")) + sql_config_read(w2); + } + fclose(fp); + ShowInfo("Done reading %s.\n", cfgName); } -int char_config_read(const char* cfgName) +int char_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars(w1); - remove_control_chars(w2); - if(strcmpi(w1,"timestamp_format") == 0) { - safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); - } else if(strcmpi(w1,"console_silent")==0){ - msg_silent = atoi(w2); - if( msg_silent ) /* only bother if its actually enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(userid, w2, sizeof(userid)); - } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(passwd, w2, sizeof(passwd)); - } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(server_name, w2, sizeof(server_name)); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); - } - } else if (strcmpi(w1, "login_ip") == 0) { - char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) { - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - char ip_str[16]; - char_ip = host2ip(w2); - if (char_ip){ - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - char ip_str[16]; - bind_ip = host2ip(w2); - if (bind_ip) { - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); - } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); - } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } else if(strcmpi(w1, "gm_allow_group") == 0) { - gm_allow_group = atoi(w2); - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); - } else if (strcmpi(w1, "start_point") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) - ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if (strcmpi(w1, "start_weapon") == 0) { - start_weapon = atoi(w2); - if (start_weapon < 0) - start_weapon = 0; - } else if (strcmpi(w1, "start_armor") == 0) { - start_armor = atoi(w2); - if (start_armor < 0) - start_armor = 0; - } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); - } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); - } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] - char_per_account = atoi(w2); - if( char_per_account == 0 || char_per_account > MAX_CHARS ) { - if( char_per_account > MAX_CHARS ) - ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); - char_per_account = MAX_CHARS; - } - } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); - } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); - } else if(strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); - } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen(cfgName, "r"); + + if (fp == NULL) { + ShowError("Configuration file not found: %s.\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars(w1); + remove_control_chars(w2); + if (strcmpi(w1,"timestamp_format") == 0) { + safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); + } else if (strcmpi(w1,"console_silent")==0) { + msg_silent = atoi(w2); + if (msg_silent) /* only bother if its actually enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } else if (strcmpi(w1,"stdout_with_ansisequence")==0) { + stdout_with_ansisequence = config_switch(w2); + } else if (strcmpi(w1, "userid") == 0) { + safestrncpy(userid, w2, sizeof(userid)); + } else if (strcmpi(w1, "passwd") == 0) { + safestrncpy(passwd, w2, sizeof(passwd)); + } else if (strcmpi(w1, "server_name") == 0) { + safestrncpy(server_name, w2, sizeof(server_name)); + } else if (strcmpi(w1, "wisp_server_name") == 0) { + if (strlen(w2) >= 4) { + safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); + } + } else if (strcmpi(w1, "login_ip") == 0) { + char ip_str[16]; + login_ip = host2ip(w2); + if (login_ip) { + safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); + ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); + } + } else if (strcmpi(w1, "login_port") == 0) { + login_port = atoi(w2); + } else if (strcmpi(w1, "char_ip") == 0) { + char ip_str[16]; + char_ip = host2ip(w2); + if (char_ip) { + safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); + ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); + } + } else if (strcmpi(w1, "bind_ip") == 0) { + char ip_str[16]; + bind_ip = host2ip(w2); + if (bind_ip) { + safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); + ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); + } + } else if (strcmpi(w1, "char_port") == 0) { + char_port = atoi(w2); + } else if (strcmpi(w1, "char_maintenance") == 0) { + char_maintenance = atoi(w2); + } else if (strcmpi(w1, "char_new") == 0) { + char_new = (bool)atoi(w2); + } else if (strcmpi(w1, "char_new_display") == 0) { + char_new_display = atoi(w2); + } else if (strcmpi(w1, "max_connect_user") == 0) { + max_connect_user = atoi(w2); + if (max_connect_user < 0) + max_connect_user = 0; // unlimited online players + } else if (strcmpi(w1, "gm_allow_group") == 0) { + gm_allow_group = atoi(w2); + } else if (strcmpi(w1, "autosave_time") == 0) { + autosave_interval = atoi(w2)*1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } else if (strcmpi(w1, "save_log") == 0) { + save_log = config_switch(w2); + } else if (strcmpi(w1, "start_point") == 0) { + char map[MAP_NAME_LENGTH_EXT]; + int x, y; + if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) + continue; + start_point.map = mapindex_name2id(map); + if (!start_point.map) + ShowError("Specified start_point %s not found in map-index cache.\n", map); + start_point.x = x; + start_point.y = y; + } else if (strcmpi(w1, "start_zeny") == 0) { + start_zeny = atoi(w2); + if (start_zeny < 0) + start_zeny = 0; + } else if (strcmpi(w1, "start_weapon") == 0) { + start_weapon = atoi(w2); + if (start_weapon < 0) + start_weapon = 0; + } else if (strcmpi(w1, "start_armor") == 0) { + start_armor = atoi(w2); + if (start_armor < 0) + start_armor = 0; + } else if (strcmpi(w1,"log_char")==0) { //log char or not [devil] + log_char = atoi(w2); + } else if (strcmpi(w1, "unknown_char_name") == 0) { + safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); + unknown_char_name[NAME_LENGTH-1] = '\0'; + } else if (strcmpi(w1, "name_ignoring_case") == 0) { + name_ignoring_case = (bool)config_switch(w2); + } else if (strcmpi(w1, "char_name_option") == 0) { + char_name_option = atoi(w2); + } else if (strcmpi(w1, "char_name_letters") == 0) { + safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); + } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] + char_per_account = atoi(w2); + if (char_per_account == 0 || char_per_account > MAX_CHARS) { + if (char_per_account > MAX_CHARS) + ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); + char_per_account = MAX_CHARS; + } + } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] + char_del_level = atoi(w2); + } else if (strcmpi(w1, "char_del_delay") == 0) { + char_del_delay = atoi(w2); + } else if (strcmpi(w1,"db_path")==0) { + safestrncpy(db_path, w2, sizeof(db_path)); + } else if (strcmpi(w1, "console") == 0) { + console = config_switch(w2); + } else if (strcmpi(w1, "fame_list_alchemist") == 0) { + fame_list_size_chemist = atoi(w2); + if (fame_list_size_chemist > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); + fame_list_size_chemist = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { + fame_list_size_smith = atoi(w2); + if (fame_list_size_smith > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); + fame_list_size_smith = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_taekwon") == 0) { + fame_list_size_taekwon = atoi(w2); + if (fame_list_size_taekwon > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); + fame_list_size_taekwon = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "guild_exp_rate") == 0) { + guild_exp_rate = atoi(w2); + } else if (strcmpi(w1, "import") == 0) { + char_config_read(w2); + } + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + return 0; } void do_final(void) { - ShowStatus("Terminating...\n"); + ShowStatus("Terminating...\n"); + + set_all_offline(-1); + set_all_offline_sql(); - set_all_offline(-1); - set_all_offline_sql(); + inter_final(); - inter_final(); + flush_fifos(); - flush_fifos(); - - do_final_mapif(); - do_final_loginif(); + do_final_mapif(); + do_final_loginif(); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db)) + Sql_ShowDebug(sql_handle); - char_db_->destroy(char_db_, NULL); - online_char_db->destroy(online_char_db, NULL); - auth_db->destroy(auth_db, NULL); + char_db_->destroy(char_db_, NULL); + online_char_db->destroy(online_char_db, NULL); + auth_db->destroy(auth_db, NULL); - if( char_fd != -1 ) - { - do_close(char_fd); - char_fd = -1; - } + if (char_fd != -1) { + do_close(char_fd); + char_fd = -1; + } - Sql_Free(sql_handle); - mapindex_final(); + Sql_Free(sql_handle); + mapindex_final(); - ShowStatus("Finished.\n"); + ShowStatus("Finished.\n"); } //------------------------------ @@ -4674,111 +4607,107 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_CHAR; + SERVER_TYPE = ATHENA_SERVER_CHAR; } /// Called when a terminate signal is received. void do_shutdown(void) { - if( runflag != CHARSERVER_ST_SHUTDOWN ) - { - int id; - runflag = CHARSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - loginif_check_shutdown(); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if (runflag != CHARSERVER_ST_SHUTDOWN) { + int id; + runflag = CHARSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + mapif_server_reset(id); + loginif_check_shutdown(); + flush_fifos(); + runflag = CORE_ST_STOP; + } } int do_init(int argc, char **argv) { - //Read map indexes - mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); - - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); - sql_config_read(SQL_CONF_NAME); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); - ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); - } - - inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration - - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_sql_init(); - char_read_fame_list(); //Read fame lists. - - if ((naddr_ != 0) && (!login_ip || !char_ip)) - { - char ip_str[16]; - ip2str(addr_[0], ip_str); - - if (naddr_ > 1) - ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); - else - ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); - char_ip = str2ip(char_ip_str); - } - } - - do_init_loginif(); - do_init_mapif(); - - // periodically update the overall user count on all mapservers + login server - add_timer_func_list(broadcast_user_count, "broadcast_user_count"); - add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); - - // Timer to clear (online_char_db) - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // Online Data timers (checking if char still connected) - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - if( console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - //Cleaning the tables for NULL entrys @ startup [Sirius] - //Chardb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - - //guilddb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); - - //guildmemberdb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - - set_defaultparse(parse_char); - char_fd = make_listen_bind(bind_ip, char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - if( runflag != CORE_ST_STOP ) - { - shutdown_callback = do_shutdown; - runflag = CHARSERVER_ST_RUNNING; - } - - return 0; + //Read map indexes + mapindex_init(); + start_point.map = mapindex_name2id("new_zone01"); + + char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); + char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); + sql_config_read(SQL_CONF_NAME); + + if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); + ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); + } + + inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration + + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); + mmo_char_sql_init(); + char_read_fame_list(); //Read fame lists. + + if ((naddr_ != 0) && (!login_ip || !char_ip)) { + char ip_str[16]; + ip2str(addr_[0], ip_str); + + if (naddr_ > 1) + ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); + else + ShowStatus("Defaulting to %s as our IP address\n", ip_str); + if (!login_ip) { + safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); + login_ip = str2ip(login_ip_str); + } + if (!char_ip) { + safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); + char_ip = str2ip(char_ip_str); + } + } + + do_init_loginif(); + do_init_mapif(); + + // periodically update the overall user count on all mapservers + login server + add_timer_func_list(broadcast_user_count, "broadcast_user_count"); + add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); + + // Timer to clear (online_char_db) + add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); + + // Online Data timers (checking if char still connected) + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); + + if (console) { + //##TODO invoke a CONSOLE_START plugin event + } + + //Cleaning the tables for NULL entrys @ startup [Sirius] + //Chardb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db)) + Sql_ShowDebug(sql_handle); + + //guilddb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db)) + Sql_ShowDebug(sql_handle); + + //guildmemberdb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db)) + Sql_ShowDebug(sql_handle); + + set_defaultparse(parse_char); + char_fd = make_listen_bind(bind_ip, char_port); + ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); + + if (runflag != CORE_ST_STOP) { + shutdown_callback = do_shutdown; + runflag = CHARSERVER_ST_RUNNING; + } + + return 0; } diff --git a/src/char/char.h b/src/char/char.h index dd1c80f9d..cdef28718 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -6,11 +6,10 @@ #include "../common/core.h" // CORE_ST_LAST -enum E_CHARSERVER_ST -{ - CHARSERVER_ST_RUNNING = CORE_ST_LAST, - CHARSERVER_ST_SHUTDOWN, - CHARSERVER_ST_LAST +enum E_CHARSERVER_ST { + CHARSERVER_ST_RUNNING = CORE_ST_LAST, + CHARSERVER_ST_SHUTDOWN, + CHARSERVER_ST_LAST }; struct mmo_charstatus; @@ -20,10 +19,10 @@ struct mmo_charstatus; #define DEFAULT_AUTOSAVE_INTERVAL 300*1000 enum { - TABLE_INVENTORY, - TABLE_CART, - TABLE_STORAGE, - TABLE_GUILD_STORAGE, + TABLE_INVENTORY, + TABLE_CART, + TABLE_STORAGE, + TABLE_GUILD_STORAGE, }; int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); @@ -37,7 +36,7 @@ int char_child(int parent_id, int child_id); int char_family(int pl1,int pl2,int pl3); int request_accreg2(int account_id, int char_id); -int save_accreg2(unsigned char* buf, int len); +int save_accreg2(unsigned char *buf, int len); extern int char_name_option; extern char char_name_letters[]; diff --git a/src/char/int_auction.c b/src/char/int_auction.c index 4fc9215a0..4eadb4866 100644 --- a/src/char/int_auction.c +++ b/src/char/int_auction.c @@ -18,442 +18,435 @@ #include #include -static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data* +static DBMap *auction_db_ = NULL; // int auction_id -> struct auction_data* void auction_delete(struct auction_data *auction); static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data); static int auction_count(int char_id, bool buy) { - int i = 0; - struct auction_data *auction; - DBIterator *iter = db_iterator(auction_db_); - - for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) - { - if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) ) - i++; - } - dbi_destroy(iter); - - return i; + int i = 0; + struct auction_data *auction; + DBIterator *iter = db_iterator(auction_db_); + + for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { + if ((buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id)) + i++; + } + dbi_destroy(iter); + + return i; } void auction_save(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", - auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); - StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + int j; + StringBuf buf; + SqlStmt *stmt; + + if (!auction) + return; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", + auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); + StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); } unsigned int auction_create(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return false; - - auction->timestamp = time(NULL) + (auction->hours * 3600); - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", - auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - auction->auction_id = 0; - } - else - { - struct auction_data *auction_; - unsigned int tick = auction->hours * 3600000; - - auction->item.amount = 1; - auction->item.identify = 1; - auction->item.expire_time = 0; - - auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); - auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0); - ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); - - CREATE(auction_, struct auction_data, 1); - memcpy(auction_, auction, sizeof(struct auction_data)); - idb_put(auction_db_, auction_->auction_id, auction_); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return auction->auction_id; + int j; + StringBuf buf; + SqlStmt *stmt; + + if (!auction) + return false; + + auction->timestamp = time(NULL) + (auction->hours * 3600); + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", + auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + auction->auction_id = 0; + } else { + struct auction_data *auction_; + unsigned int tick = auction->hours * 3600000; + + auction->item.amount = 1; + auction->item.identify = 1; + auction->item.expire_time = 0; + + auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); + auction->auction_end_timer = add_timer(gettick() + tick , auction_end_timer, auction->auction_id, 0); + ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); + + CREATE(auction_, struct auction_data, 1); + memcpy(auction_, auction, sizeof(struct auction_data)); + idb_put(auction_db_, auction_->auction_id, auction_); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return auction->auction_id; } static void mapif_Auction_message(int char_id, unsigned char result) { - unsigned char buf[74]; - - WBUFW(buf,0) = 0x3854; - WBUFL(buf,2) = char_id; - WBUFL(buf,6) = result; - mapif_sendall(buf,7); + unsigned char buf[74]; + + WBUFW(buf,0) = 0x3854; + WBUFL(buf,2) = char_id; + WBUFL(buf,6) = result; + mapif_sendall(buf,7); } static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct auction_data *auction; - if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL ) - { - if( auction->buyer_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); - } - else - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); - - ShowInfo("Auction End: id %u.\n", auction->auction_id); - - auction->auction_end_timer = INVALID_TIMER; - auction_delete(auction); - } - - return 0; + struct auction_data *auction; + if ((auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL) { + if (auction->buyer_id) { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); + } else + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); + + ShowInfo("Auction End: id %u.\n", auction->auction_id); + + auction->auction_end_timer = INVALID_TIMER; + auction_delete(auction); + } + + return 0; } void auction_delete(struct auction_data *auction) { - unsigned int auction_id = auction->auction_id; + unsigned int auction_id = auction->auction_id; - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id)) + Sql_ShowDebug(sql_handle); - if( auction->auction_end_timer != INVALID_TIMER ) - delete_timer(auction->auction_end_timer, auction_end_timer); + if (auction->auction_end_timer != INVALID_TIMER) + delete_timer(auction->auction_end_timer, auction_end_timer); - idb_remove(auction_db_, auction_id); + idb_remove(auction_db_, auction_id); } void inter_auctions_fromsql(void) { - int i; - struct auction_data *auction; - struct item *item; - char *data; - StringBuf buf; - unsigned int tick = gettick(), endtick; - time_t now = time(NULL); - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," - "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); - for( i = 0; i < MAX_SLOTS; i++ ) - StringBuf_Printf(&buf, ",`card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - CREATE(auction, struct auction_data, 1); - Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); - - item = &auction->item; - Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); - Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); - - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - - item->identify = 1; - item->amount = 1; - item->expire_time = 0; - - for( i = 0; i < MAX_SLOTS; i++ ) - { - Sql_GetData(sql_handle, 14 + i, &data, NULL); - item->card[i] = atoi(data); - } - - if( auction->timestamp > now ) - endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; - else - endtick = tick + 10000; // 10 Second's to process ended auctions - - auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); - idb_put(auction_db_, auction->auction_id, auction); - } - - Sql_FreeResult(sql_handle); + int i; + struct auction_data *auction; + struct item *item; + char *data; + StringBuf buf; + unsigned int tick = gettick(), endtick; + time_t now = time(NULL); + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," + "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + CREATE(auction, struct auction_data, 1); + Sql_GetData(sql_handle, 0, &data, NULL); + auction->auction_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + auction->seller_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(auction->seller_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 3, &data, NULL); + auction->buyer_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + safestrncpy(auction->buyer_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 5, &data, NULL); + auction->price = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + auction->buynow = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + auction->hours = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + auction->timestamp = atoi(data); + + item = &auction->item; + Sql_GetData(sql_handle, 9, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); + safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); + Sql_GetData(sql_handle,11, &data, NULL); + auction->type = atoi(data); + + Sql_GetData(sql_handle,12, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + item->attribute = atoi(data); + + item->identify = 1; + item->amount = 1; + item->expire_time = 0; + + for (i = 0; i < MAX_SLOTS; i++) { + Sql_GetData(sql_handle, 14 + i, &data, NULL); + item->card[i] = atoi(data); + } + + if (auction->timestamp > now) + endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; + else + endtick = tick + 10000; // 10 Second's to process ended auctions + + auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); + idb_put(auction_db_, auction->auction_id, auction); + } + + Sql_FreeResult(sql_handle); } static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf) { - int len = (sizeof(struct auction_data) * count) + 12; - - WFIFOHEAD(fd, len); - WFIFOW(fd,0) = 0x3850; - WFIFOW(fd,2) = len; - WFIFOL(fd,4) = char_id; - WFIFOW(fd,8) = count; - WFIFOW(fd,10) = pages; - memcpy(WFIFOP(fd,12), buf, len - 12); - WFIFOSET(fd,len); + int len = (sizeof(struct auction_data) * count) + 12; + + WFIFOHEAD(fd, len); + WFIFOW(fd,0) = 0x3850; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = char_id; + WFIFOW(fd,8) = count; + WFIFOW(fd,10) = pages; + memcpy(WFIFOP(fd,12), buf, len - 12); + WFIFOSET(fd,len); } static void mapif_parse_Auction_requestlist(int fd) { - char searchtext[NAME_LENGTH]; - int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); - int price = RFIFOL(fd,10); - short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); - unsigned char buf[5 * sizeof(struct auction_data)]; - DBIterator *iter = db_iterator(auction_db_); - struct auction_data *auction; - short i = 0, j = 0, pages = 1; - - memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); - - for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) - { - if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || - (type == 1 && auction->type != IT_WEAPON) || - (type == 2 && auction->type != IT_CARD) || - (type == 3 && auction->type != IT_ETC) || - (type == 4 && !strstr(auction->item_name, searchtext)) || - (type == 5 && auction->price > price) || - (type == 6 && auction->seller_id != char_id) || - (type == 7 && auction->buyer_id != char_id) ) - continue; - - i++; - if( i > 5 ) - { // Counting Pages of Total Results (5 Results per Page) - pages++; - i = 1; // First Result of This Page - } - - if( page != pages ) - continue; // This is not the requested Page - - memcpy(WBUFP(buf, j * len), auction, len); - j++; // Found Results - } - dbi_destroy(iter); - - mapif_Auction_sendlist(fd, char_id, j, pages, buf); + char searchtext[NAME_LENGTH]; + int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); + int price = RFIFOL(fd,10); + short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); + unsigned char buf[5 * sizeof(struct auction_data)]; + DBIterator *iter = db_iterator(auction_db_); + struct auction_data *auction; + short i = 0, j = 0, pages = 1; + + memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); + + for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { + if ((type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || + (type == 1 && auction->type != IT_WEAPON) || + (type == 2 && auction->type != IT_CARD) || + (type == 3 && auction->type != IT_ETC) || + (type == 4 && !strstr(auction->item_name, searchtext)) || + (type == 5 && auction->price > price) || + (type == 6 && auction->seller_id != char_id) || + (type == 7 && auction->buyer_id != char_id)) + continue; + + i++; + if (i > 5) { + // Counting Pages of Total Results (5 Results per Page) + pages++; + i = 1; // First Result of This Page + } + + if (page != pages) + continue; // This is not the requested Page + + memcpy(WBUFP(buf, j * len), auction, len); + j++; // Found Results + } + dbi_destroy(iter); + + mapif_Auction_sendlist(fd, char_id, j, pages, buf); } static void mapif_Auction_register(int fd, struct auction_data *auction) { - int len = sizeof(struct auction_data) + 4; + int len = sizeof(struct auction_data) + 4; - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x3851; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); - WFIFOSET(fd,len); + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x3851; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); + WFIFOSET(fd,len); } static void mapif_parse_Auction_register(int fd) { - struct auction_data auction; - if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 ) - return; + struct auction_data auction; + if (RFIFOW(fd,2) != sizeof(struct auction_data) + 4) + return; - memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); - if( auction_count(auction.seller_id, false) < 5 ) - auction.auction_id = auction_create(&auction); + memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); + if (auction_count(auction.seller_id, false) < 5) + auction.auction_id = auction_create(&auction); - mapif_Auction_register(fd, &auction); + mapif_Auction_register(fd, &auction); } static void mapif_Auction_cancel(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3852; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3852; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_cancel(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction - return; - } - - if( auction->buyer_id > 0 ) - { - mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled - return; - } - - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); - auction_delete(auction); - - mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { + mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect + return; + } + + if (auction->seller_id != char_id) { + mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction + return; + } + + if (auction->buyer_id > 0) { + mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled + return; + } + + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); + auction_delete(auction); + + mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled } static void mapif_Auction_close(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3853; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3853; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_close(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - if( auction->buyer_id == 0 ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - // Send Money to Seller - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); - // Send Item to Buyer - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - auction_delete(auction); - - mapif_Auction_close(fd, char_id, 0); // You have ended the auction + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { + mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect + return; + } + + if (auction->seller_id != char_id) { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + if (auction->buyer_id == 0) { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + // Send Money to Seller + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); + // Send Item to Buyer + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + auction_delete(auction); + + mapif_Auction_close(fd, char_id, 0); // You have ended the auction } static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x3855; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = bid; // To Return Zeny - WFIFOB(fd,10) = result; - WFIFOSET(fd,11); + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x3855; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = bid; // To Return Zeny + WFIFOB(fd,10) = result; + WFIFOSET(fd,11); } static void mapif_parse_Auction_bid(int fd) { - int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); - unsigned int auction_id = RFIFOL(fd,8); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction - return; - } - - if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time - return; - } - - if( auction->buyer_id > 0 ) - { // Send Money back to the previous Buyer - if( auction->buyer_id != char_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); - mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction - } - else - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); - } - - auction->buyer_id = char_id; - safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH); - auction->price = bid; - - if( bid >= auction->buynow ) - { // Automatic won the auction - mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction - - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); - mapif_Auction_message(char_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); - - auction_delete(auction); - return; - } - - auction_save(auction); - - mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction + int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); + unsigned int auction_id = RFIFOL(fd,8); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id) { + mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction + return; + } + + if (auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id) { + mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time + return; + } + + if (auction->buyer_id > 0) { + // Send Money back to the previous Buyer + if (auction->buyer_id != char_id) { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); + mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction + } else + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); + } + + auction->buyer_id = char_id; + safestrncpy(auction->buyer_name, (char *)RFIFOP(fd,16), NAME_LENGTH); + auction->price = bid; + + if (bid >= auction->buynow) { + // Automatic won the auction + mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction + + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); + mapif_Auction_message(char_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); + + auction_delete(auction); + return; + } + + auction_save(auction); + + mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction } /*========================================== @@ -461,30 +454,39 @@ static void mapif_parse_Auction_bid(int fd) *------------------------------------------*/ int inter_auction_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3050: mapif_parse_Auction_requestlist(fd); break; - case 0x3051: mapif_parse_Auction_register(fd); break; - case 0x3052: mapif_parse_Auction_cancel(fd); break; - case 0x3053: mapif_parse_Auction_close(fd); break; - case 0x3055: mapif_parse_Auction_bid(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3050: + mapif_parse_Auction_requestlist(fd); + break; + case 0x3051: + mapif_parse_Auction_register(fd); + break; + case 0x3052: + mapif_parse_Auction_cancel(fd); + break; + case 0x3053: + mapif_parse_Auction_close(fd); + break; + case 0x3055: + mapif_parse_Auction_bid(fd); + break; + default: + return 0; + } + return 1; } int inter_auction_sql_init(void) { - auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - inter_auctions_fromsql(); + auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + inter_auctions_fromsql(); - return 0; + return 0; } void inter_auction_sql_final(void) { - auction_db_->destroy(auction_db_,NULL); + auction_db_->destroy(auction_db_,NULL); - return; + return; } diff --git a/src/char/int_elemental.c b/src/char/int_elemental.c index 7c76c4496..aa7ef5f65 100644 --- a/src/char/int_elemental.c +++ b/src/char/int_elemental.c @@ -15,147 +15,179 @@ #include #include -bool mapif_elemental_save(struct s_elemental* ele) { - bool flag = true; - - if( ele->elemental_id == 0 ) { // Create new DB entry - if( SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - ele->elemental_id = (int)Sql_LastInsertId(sql_handle); - } else if( SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," - "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," - "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, - ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id) ) - { // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } - return flag; +bool mapif_elemental_save(struct s_elemental *ele) +{ + bool flag = true; + + if (ele->elemental_id == 0) { // Create new DB entry + if (SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else + ele->elemental_id = (int)Sql_LastInsertId(sql_handle); + } else if (SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," + "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," + "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, + ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id)) { + // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } + return flag; } -bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) { - char* data; - - memset(ele, 0, sizeof(struct s_elemental)); - ele->elemental_id = ele_id; - ele->char_id = char_id; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," - "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", - ele_id, char_id) ) { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); ele->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); ele->mode = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); ele->hp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); ele->sp = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); ele->max_hp = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); ele->max_sp = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); ele->str = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); ele->agi = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); ele->vit = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); ele->int_ = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); ele->dex = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); ele->luk = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); ele->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if( save_log ) - ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); - - return true; +bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) +{ + char *data; + + memset(ele, 0, sizeof(struct s_elemental)); + ele->elemental_id = ele_id; + ele->char_id = char_id; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," + "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", + ele_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + ele->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + ele->mode = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + ele->hp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + ele->sp = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + ele->max_hp = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + ele->max_sp = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + ele->str = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + ele->agi = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + ele->vit = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + ele->int_ = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + ele->dex = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + ele->luk = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); + ele->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if (save_log) + ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); + + return true; } -bool mapif_elemental_delete(int ele_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id) ) { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; +bool mapif_elemental_delete(int ele_id) +{ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; } -static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) { - int size = sizeof(struct s_elemental) + 5; - - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x387c; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); - WFIFOSET(fd,size); +static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) +{ + int size = sizeof(struct s_elemental) + 5; + + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x387c; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); + WFIFOSET(fd,size); } -static void mapif_parse_elemental_create(int fd, struct s_elemental* ele) { - bool result = mapif_elemental_save(ele); - mapif_elemental_send(fd, ele, result); +static void mapif_parse_elemental_create(int fd, struct s_elemental *ele) +{ + bool result = mapif_elemental_save(ele); + mapif_elemental_send(fd, ele, result); } -static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) { - struct s_elemental ele; - bool result = mapif_elemental_load(ele_id, char_id, &ele); - mapif_elemental_send(fd, &ele, result); +static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) +{ + struct s_elemental ele; + bool result = mapif_elemental_load(ele_id, char_id, &ele); + mapif_elemental_send(fd, &ele, result); } -static void mapif_elemental_deleted(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387d; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_deleted(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387d; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_delete(int fd, int ele_id) { - bool result = mapif_elemental_delete(ele_id); - mapif_elemental_deleted(fd, result); +static void mapif_parse_elemental_delete(int fd, int ele_id) +{ + bool result = mapif_elemental_delete(ele_id); + mapif_elemental_deleted(fd, result); } -static void mapif_elemental_saved(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387e; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_saved(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387e; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_save(int fd, struct s_elemental* ele) { - bool result = mapif_elemental_save(ele); - mapif_elemental_saved(fd, result); +static void mapif_parse_elemental_save(int fd, struct s_elemental *ele) +{ + bool result = mapif_elemental_save(ele); + mapif_elemental_saved(fd, result); } -void inter_elemental_sql_init(void) { - return; +void inter_elemental_sql_init(void) +{ + return; } -void inter_elemental_sql_final(void) { - return; +void inter_elemental_sql_final(void) +{ + return; } /*========================================== * Inter Packets *------------------------------------------*/ -int inter_elemental_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) { - case 0x307c: mapif_parse_elemental_create(fd, (struct s_elemental*)RFIFOP(fd,4)); break; - case 0x307d: mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x307e: mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x307f: mapif_parse_elemental_save(fd, (struct s_elemental*)RFIFOP(fd,4)); break; - default: - return 0; - } - return 1; +int inter_elemental_parse_frommap(int fd) +{ + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x307c: + mapif_parse_elemental_create(fd, (struct s_elemental *)RFIFOP(fd,4)); + break; + case 0x307d: + mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x307e: + mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x307f: + mapif_parse_elemental_save(fd, (struct s_elemental *)RFIFOP(fd,4)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_guild.c b/src/char/int_guild.c index b07a1933f..2b4a9f3ac 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -31,7 +31,7 @@ static const char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; //Guild cache -static DBMap* guild_db_; // int guild_id -> struct guild* +static DBMap *guild_db_; // int guild_id -> struct guild* static DBMap *castle_db; static unsigned int guild_exp[100]; @@ -47,703 +47,703 @@ int inter_guild_tosql(struct guild *g,int flag); static int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) { - static int last_id = 0; //To know in which guild we were. - int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. - DBIterator *iter = db_iterator(guild_db_); - DBKey key; - struct guild* g; - - if( last_id == 0 ) //Save the first guild in the list. - state = 1; - - for( g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key)) ) - { - if( state == 0 && g->guild_id == last_id ) - state++; //Save next guild in the list. - else - if( state == 1 && g->save_flag&GS_MASK ) - { - inter_guild_tosql(g, g->save_flag&GS_MASK); - g->save_flag &= ~GS_MASK; - - //Some guild saved. - last_id = g->guild_id; - state++; - } - - if( g->save_flag == GS_REMOVE ) - {// Nothing to save, guild is ready for removal. - if (save_log) - ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); - db_remove(guild_db_, key); - } - } - dbi_destroy(iter); - - if( state != 2 ) //Reached the end of the guild db without saving. - last_id = 0; //Reset guild saved, return to beginning. - - state = guild_db_->size(guild_db_); - if( state < 1 ) state = 1; //Calculate the time slot for the next save. - add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); - return 0; + static int last_id = 0; //To know in which guild we were. + int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. + DBIterator *iter = db_iterator(guild_db_); + DBKey key; + struct guild *g; + + if (last_id == 0) //Save the first guild in the list. + state = 1; + + for (g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key))) { + if (state == 0 && g->guild_id == last_id) + state++; //Save next guild in the list. + else if (state == 1 && g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); + g->save_flag &= ~GS_MASK; + + //Some guild saved. + last_id = g->guild_id; + state++; + } + + if (g->save_flag == GS_REMOVE) { + // Nothing to save, guild is ready for removal. + if (save_log) + ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); + db_remove(guild_db_, key); + } + } + dbi_destroy(iter); + + if (state != 2) //Reached the end of the guild db without saving. + last_id = 0; //Reset guild saved, return to beginning. + + state = guild_db_->size(guild_db_); + if (state < 1) state = 1; //Calculate the time slot for the next save. + add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); + return 0; } int inter_guild_removemember_tosql(int account_id, int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + return 0; } // Save guild into sql int inter_guild_tosql(struct guild *g,int flag) { - // Table guild (GS_BASIC_MASK) - // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` - // GS_CONNECT `connect_member`,`average_lv` - // GS_MES `mes1`,`mes2` - // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` - // GS_BASIC `name`,`master`,`char_id` - - // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) - // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) - // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) - // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) - // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) - - // temporary storage for str convertion. They must be twice the size of the - // original string to ensure no overflows will occur. [Skotlex] - char t_info[256]; - char esc_name[NAME_LENGTH*2+1]; - char esc_master[NAME_LENGTH*2+1]; - char new_guild = 0; - int i=0; - - if (g->guild_id<=0 && g->guild_id != -1) return 0; - + // Table guild (GS_BASIC_MASK) + // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` + // GS_CONNECT `connect_member`,`average_lv` + // GS_MES `mes1`,`mes2` + // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` + // GS_BASIC `name`,`master`,`char_id` + + // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) + // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) + // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) + // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) + // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) + + // temporary storage for str convertion. They must be twice the size of the + // original string to ensure no overflows will occur. [Skotlex] + char t_info[256]; + char esc_name[NAME_LENGTH*2+1]; + char esc_master[NAME_LENGTH*2+1]; + char new_guild = 0; + int i=0; + + if (g->guild_id<=0 && g->guild_id != -1) return 0; + #ifdef NOISY - ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); + ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); #endif - Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); - *t_info = '\0'; - - // Insert a new guild the guild - if (flag&GS_BASIC && g->guild_id == -1) - { - strcat(t_info, " guild_create"); - - // Create a new guild - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " - "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) - { - Sql_ShowDebug(sql_handle); - if (g->guild_id == -1) - return 0; //Failed to create guild! - } - else - { - g->guild_id = (int)Sql_LastInsertId(sql_handle); - new_guild = 1; - } - } - - // If we need an update on an existing guild or more update on the new guild - if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) - { - StringBuf buf; - bool add_comma = false; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); - - if (flag & GS_EMBLEM) - { - char emblem_data[sizeof(g->emblem_data)*2+1]; - char* pData = emblem_data; - - strcat(t_info, " emblem"); - // Convert emblem_data to hex - //TODO: why not use binary directly? [ultramage] - for(i=0; iemblem_len; i++){ - *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; - *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; - } - *pData = 0; - StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); - add_comma = true; - } - if (flag & GS_BASIC) - { - strcat(t_info, " basic"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); - } - if (flag & GS_CONNECT) - { - strcat(t_info, " connect"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); - } - if (flag & GS_MES) - { - char esc_mes1[sizeof(g->mes1)*2+1]; - char esc_mes2[sizeof(g->mes2)*2+1]; - - strcat(t_info, " mes"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); - Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); - StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); - } - if (flag & GS_LEVEL) - { - strcat(t_info, " level"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); - } - StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } - - if (flag&GS_MEMBER) - { - struct guild_member *m; - - strcat(t_info, " members"); - // Update only needed players - for(i=0;imax_member;i++){ - m = &g->member[i]; - if (!m->modified) - continue; - if(m->account_id) { - //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO - Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", - guild_member_db, g->guild_id, m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) - Sql_ShowDebug(sql_handle); - if (m->modified & GS_MEMBER_NEW) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", - char_db, g->guild_id, m->char_id) ) - Sql_ShowDebug(sql_handle); - } - m->modified = GS_MEMBER_UNMODIFIED; - } - } - } - - if (flag&GS_POSITION){ - strcat(t_info, " positions"); - //printf("- Insert guild %d to guild_position\n",g->guild_id); - for(i=0;iposition[i]; - if (!p->modified) - continue; - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", - guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) - Sql_ShowDebug(sql_handle); - p->modified = GS_POSITION_UNMODIFIED; - } - } - - if (flag&GS_ALLIANCE) - { - // Delete current alliances - // NOTE: no need to do it on both sides since both guilds in memory had - // their info changed, not to mention this would also mess up oppositions! - // [Skotlex] - //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) - { - Sql_ShowDebug(sql_handle); - } - else - { - //printf("- Insert guild %d to guild_alliance\n",g->guild_id); - for(i=0;ialliance[i]; - if(a->guild_id>0) - { - Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " - "VALUES ('%d','%d','%d','%s')", - guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - } - } - } - - if (flag&GS_EXPULSION){ - strcat(t_info, " expulsions"); - //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); - for(i=0;iexpulsion[i]; - if(e->account_id>0){ - char esc_mes[sizeof(e->mes)*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " - "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (flag&GS_SKILL){ - strcat(t_info, " skills"); - //printf("- Insert guild %d to guild_skill\n",g->guild_id); - for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", - guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (save_log) - ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); + *t_info = '\0'; + + // Insert a new guild the guild + if (flag&GS_BASIC && g->guild_id == -1) { + strcat(t_info, " guild_create"); + + // Create a new guild + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " + "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", + guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id)) { + Sql_ShowDebug(sql_handle); + if (g->guild_id == -1) + return 0; //Failed to create guild! + } else { + g->guild_id = (int)Sql_LastInsertId(sql_handle); + new_guild = 1; + } + } + + // If we need an update on an existing guild or more update on the new guild + if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) { + StringBuf buf; + bool add_comma = false; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); + + if (flag & GS_EMBLEM) { + char emblem_data[sizeof(g->emblem_data)*2+1]; + char *pData = emblem_data; + + strcat(t_info, " emblem"); + // Convert emblem_data to hex + //TODO: why not use binary directly? [ultramage] + for (i=0; iemblem_len; i++) { + *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; + *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; + } + *pData = 0; + StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); + add_comma = true; + } + if (flag & GS_BASIC) { + strcat(t_info, " basic"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); + } + if (flag & GS_CONNECT) { + strcat(t_info, " connect"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); + } + if (flag & GS_MES) { + char esc_mes1[sizeof(g->mes1)*2+1]; + char esc_mes2[sizeof(g->mes2)*2+1]; + + strcat(t_info, " mes"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); + Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); + StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); + } + if (flag & GS_LEVEL) { + strcat(t_info, " level"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); + } + StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } + + if (flag&GS_MEMBER) { + struct guild_member *m; + + strcat(t_info, " members"); + // Update only needed players + for (i=0; imax_member; i++) { + m = &g->member[i]; + if (!m->modified) + continue; + if (m->account_id) { + //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO + Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", + guild_member_db, g->guild_id, m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name)) + Sql_ShowDebug(sql_handle); + if (m->modified & GS_MEMBER_NEW) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", + char_db, g->guild_id, m->char_id)) + Sql_ShowDebug(sql_handle); + } + m->modified = GS_MEMBER_UNMODIFIED; + } + } + } + + if (flag&GS_POSITION) { + strcat(t_info, " positions"); + //printf("- Insert guild %d to guild_position\n",g->guild_id); + for (i=0; iposition[i]; + if (!p->modified) + continue; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", + guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode)) + Sql_ShowDebug(sql_handle); + p->modified = GS_POSITION_UNMODIFIED; + } + } + + if (flag&GS_ALLIANCE) { + // Delete current alliances + // NOTE: no need to do it on both sides since both guilds in memory had + // their info changed, not to mention this would also mess up oppositions! + // [Skotlex] + //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id)) { + Sql_ShowDebug(sql_handle); + } else { + //printf("- Insert guild %d to guild_alliance\n",g->guild_id); + for (i=0; ialliance[i]; + if (a->guild_id>0) { + Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " + "VALUES ('%d','%d','%d','%s')", + guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name)) + Sql_ShowDebug(sql_handle); + } + } + } + } + + if (flag&GS_EXPULSION) { + strcat(t_info, " expulsions"); + //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); + for (i=0; iexpulsion[i]; + if (e->account_id>0) { + char esc_mes[sizeof(e->mes)*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " + "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes)) + Sql_ShowDebug(sql_handle); + } + } + } + + if (flag&GS_SKILL) { + strcat(t_info, " skills"); + //printf("- Insert guild %d to guild_skill\n",g->guild_id); + for (i=0; iskill[i].id>0 && g->skill[i].lv>0) { + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", + guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv)) + Sql_ShowDebug(sql_handle); + } + } + } + + if (save_log) + ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); + return 1; } // Read guild from sql -struct guild * inter_guild_fromsql(int guild_id) -{ - struct guild *g; - char* data; - size_t len; - char* p; - int i; +struct guild *inter_guild_fromsql(int guild_id) { + struct guild *g; + char *data; + size_t len; + char *p; + int i; - if( guild_id <= 0 ) - return NULL; + if (guild_id <= 0) + return NULL; - g = (struct guild*)idb_get(guild_db_, guild_id); - if( g ) - return g; + g = (struct guild *)idb_get(guild_db_, guild_id); + if (g) + return g; #ifdef NOISY - ShowInfo("Guild load request (%d)...\n", guild_id); + ShowInfo("Guild load request (%d)...\n", guild_id); #endif - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " - "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL;// Guild does not exists. - - CREATE(g, struct guild, 1); - - g->guild_id = guild_id; - Sql_GetData(sql_handle, 0, &data, &len); memcpy(g->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(g->master, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); g->guild_lv = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); g->connect_member = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); g->max_member = atoi(data); - if( g->max_member > MAX_GUILD ) - { // Fix reduction of MAX_GUILD [PoW] - ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - Sql_GetData(sql_handle, 5, &data, NULL); g->average_lv = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); g->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); g->next_exp = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); g->skill_point = atoi(data); - Sql_GetData(sql_handle, 9, &data, &len); memcpy(g->mes1, data, min(len, sizeof(g->mes1))); - Sql_GetData(sql_handle, 10, &data, &len); memcpy(g->mes2, data, min(len, sizeof(g->mes2))); - Sql_GetData(sql_handle, 11, &data, &len); g->emblem_len = atoi(data); - Sql_GetData(sql_handle, 12, &data, &len); g->emblem_id = atoi(data); - Sql_GetData(sql_handle, 13, &data, &len); - // convert emblem data from hexadecimal to binary - //TODO: why not store it in the db as binary directly? [ultramage] - for( i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p ) - { - if( *data >= '0' && *data <= '9' ) - *p = *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p = *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p = *data - 'A' + 10; - *p <<= 4; - ++data; - - if( *data >= '0' && *data <= '9' ) - *p |= *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p |= *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p |= *data - 'A' + 10; - ++data; - } - - // load guild member info - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " - "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_member* m = &g->member[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); m->hair = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); m->hair_color = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->gender = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->class_ = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); m->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); m->exp_payper = (unsigned int)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); m->online = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); m->position = atoi(data); - if( m->position >= MAX_GUILDPOSITION ) // Fix reduction of MAX_GUILDPOSITION [PoW] - m->position = MAX_GUILDPOSITION - 1; - Sql_GetData(sql_handle, 11, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - m->modified = GS_MEMBER_UNMODIFIED; - } - - //printf("- Read guild_position %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int position; - struct guild_position* p; - - Sql_GetData(sql_handle, 0, &data, NULL); position = atoi(data); - if( position < 0 || position >= MAX_GUILDPOSITION ) - continue;// invalid position - p = &g->position[position]; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->mode = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); p->exp_mode = atoi(data); - p->modified = GS_POSITION_UNMODIFIED; - } - - //printf("- Read guild_alliance %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_alliance* a = &g->alliance[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); a->opposition = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); a->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); - } - - //printf("- Read guild_expulsion %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_expulsion *e = &g->expulsion[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); e->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(e->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(e->mes, data, min(len, sizeof(e->mes))); - } - - //printf("- Read guild_skill %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - - for(i = 0; i < MAX_GUILDSKILL; i++) - { //Skill IDs must always be initialized. [Skotlex] - g->skill[i].id = i + GD_SKILLBASE; - } - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int id; - Sql_GetData(sql_handle, 0, &data, NULL); id = atoi(data) - GD_SKILLBASE; - if( id < 0 && id >= MAX_GUILDSKILL ) - continue;// invalid guild skill - Sql_GetData(sql_handle, 1, &data, NULL); g->skill[id].lv = atoi(data); - } - Sql_FreeResult(sql_handle); - - idb_put(guild_db_, guild_id, g); //Add to cache - g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. - - if (save_log) - ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); - - return g; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " + "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return NULL;// Guild does not exists. + + CREATE(g, struct guild, 1); + + g->guild_id = guild_id; + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(g->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(g->master, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + g->guild_lv = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + g->connect_member = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + g->max_member = atoi(data); + if (g->max_member > MAX_GUILD) { + // Fix reduction of MAX_GUILD [PoW] + ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + Sql_GetData(sql_handle, 5, &data, NULL); + g->average_lv = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + g->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); + g->next_exp = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + g->skill_point = atoi(data); + Sql_GetData(sql_handle, 9, &data, &len); + memcpy(g->mes1, data, min(len, sizeof(g->mes1))); + Sql_GetData(sql_handle, 10, &data, &len); + memcpy(g->mes2, data, min(len, sizeof(g->mes2))); + Sql_GetData(sql_handle, 11, &data, &len); + g->emblem_len = atoi(data); + Sql_GetData(sql_handle, 12, &data, &len); + g->emblem_id = atoi(data); + Sql_GetData(sql_handle, 13, &data, &len); + // convert emblem data from hexadecimal to binary + //TODO: why not store it in the db as binary directly? [ultramage] + for (i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p) { + if (*data >= '0' && *data <= '9') + *p = *data - '0'; + else if (*data >= 'a' && *data <= 'f') + *p = *data - 'a' + 10; + else if (*data >= 'A' && *data <= 'F') + *p = *data - 'A' + 10; + *p <<= 4; + ++data; + + if (*data >= '0' && *data <= '9') + *p |= *data - '0'; + else if (*data >= 'a' && *data <= 'f') + *p |= *data - 'a' + 10; + else if (*data >= 'A' && *data <= 'F') + *p |= *data - 'A' + 10; + ++data; + } + + // load guild member info + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " + "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_member *m = &g->member[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + m->hair = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + m->hair_color = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + m->gender = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + m->class_ = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + m->lv = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + m->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + m->exp_payper = (unsigned int)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + m->online = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + m->position = atoi(data); + if (m->position >= MAX_GUILDPOSITION) // Fix reduction of MAX_GUILDPOSITION [PoW] + m->position = MAX_GUILDPOSITION - 1; + Sql_GetData(sql_handle, 11, &data, &len); + memcpy(m->name, data, min(len, NAME_LENGTH)); + m->modified = GS_MEMBER_UNMODIFIED; + } + + //printf("- Read guild_position %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int position; + struct guild_position *p; + + Sql_GetData(sql_handle, 0, &data, NULL); + position = atoi(data); + if (position < 0 || position >= MAX_GUILDPOSITION) + continue;// invalid position + p = &g->position[position]; + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + p->mode = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + p->exp_mode = atoi(data); + p->modified = GS_POSITION_UNMODIFIED; + } + + //printf("- Read guild_alliance %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_alliance *a = &g->alliance[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + a->opposition = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + a->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(a->name, data, min(len, NAME_LENGTH)); + } + + //printf("- Read guild_expulsion %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_expulsion *e = &g->expulsion[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + e->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(e->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(e->mes, data, min(len, sizeof(e->mes))); + } + + //printf("- Read guild_skill %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + + for (i = 0; i < MAX_GUILDSKILL; i++) { + //Skill IDs must always be initialized. [Skotlex] + g->skill[i].id = i + GD_SKILLBASE; + } + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int id; + Sql_GetData(sql_handle, 0, &data, NULL); + id = atoi(data) - GD_SKILLBASE; + if (id < 0 && id >= MAX_GUILDSKILL) + continue;// invalid guild skill + Sql_GetData(sql_handle, 1, &data, NULL); + g->skill[id].lv = atoi(data); + } + Sql_FreeResult(sql_handle); + + idb_put(guild_db_, guild_id, g); //Add to cache + g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. + + if (save_log) + ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); + + return g; } // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) int inter_guildcastle_tosql(struct guild_castle *gc) { - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " - "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", - guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, - gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - else if(save_log) - ShowInfo("Saved guild castle (%d)\n", gc->castle_id); - - StringBuf_Destroy(&buf); - return 0; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " + "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", + guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, + gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + else if (save_log) + ShowInfo("Saved guild castle (%d)\n", gc->castle_id); + + StringBuf_Destroy(&buf); + return 0; } // Read guild_castle from SQL -static struct guild_castle* inter_guildcastle_fromsql(int castle_id) -{ - char *data; - int i; - StringBuf buf; - struct guild_castle *gc = idb_get(castle_db, castle_id); - - if (gc != NULL) - return gc; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " - "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - return NULL; - } - StringBuf_Destroy(&buf); - - CREATE(gc, struct guild_castle, 1); - gc->castle_id = castle_id; - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); - for (i = 10; i < 10+MAX_GUARDIANS; i++) { - Sql_GetData(sql_handle, i, &data, NULL); gc->guardian[i-10].visible = atoi(data); - } - } - Sql_FreeResult(sql_handle); - - idb_put(castle_db, castle_id, gc); - - if (save_log) - ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); - - return gc; +static struct guild_castle *inter_guildcastle_fromsql(int castle_id) { + char *data; + int i; + StringBuf buf; + struct guild_castle *gc = idb_get(castle_db, castle_id); + + if (gc != NULL) + return gc; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " + "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + return NULL; + } + StringBuf_Destroy(&buf); + + CREATE(gc, struct guild_castle, 1); + gc->castle_id = castle_id; + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 1, &data, NULL); + gc->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + gc->economy = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + gc->defense = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + gc->triggerE = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + gc->triggerD = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + gc->nextTime = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + gc->payTime = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + gc->createTime = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + gc->visibleC = atoi(data); + for (i = 10; i < 10+MAX_GUARDIANS; i++) { + Sql_GetData(sql_handle, i, &data, NULL); + gc->guardian[i-10].visible = atoi(data); + } + } + Sql_FreeResult(sql_handle); + + idb_put(castle_db, castle_id, gc); + + if (save_log) + ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); + + return gc; } // Read exp_guild.txt int inter_guild_ReadEXP(void) { - int i; - FILE *fp; - char line[1024]; - for (i=0;i<100;i++) guild_exp[i]=0; - //this is going to be discussed, temp fix - sprintf(line, "%s/pre-re/exp_guild.txt", db_path); - fp=fopen(line,"r"); - if(fp==NULL){ - ShowError("can't read %s\n", line); - return 1; - } - i=0; - while(fgets(line, sizeof(line), fp) && i < 100) - { - if(line[0]=='/' && line[1]=='/') - continue; - guild_exp[i]=(unsigned int)atof(line); - i++; - } - fclose(fp); - - return 0; + int i; + FILE *fp; + char line[1024]; + for (i=0; i<100; i++) guild_exp[i]=0; + //this is going to be discussed, temp fix + sprintf(line, "%s/pre-re/exp_guild.txt", db_path); + fp=fopen(line,"r"); + if (fp==NULL) { + ShowError("can't read %s\n", line); + return 1; + } + i=0; + while (fgets(line, sizeof(line), fp) && i < 100) { + if (line[0]=='/' && line[1]=='/') + continue; + guild_exp[i]=(unsigned int)atof(line); + i++; + } + fclose(fp); + + return 0; } int inter_guild_CharOnline(int char_id, int guild_id) { - struct guild *g; - int i; - - if (guild_id == -1) { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - g = inter_guild_fromsql(guild_id); - if(!g) { - ShowError("Character %d's guild %d not found!\n", char_id, guild_id); - return 0; - } - - //Member has logged in before saving, tell saver not to delete - if(g->save_flag & GS_REMOVE) - g->save_flag &= ~GS_REMOVE; - - //Set member online - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 1; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - return 1; + struct guild *g; + int i; + + if (guild_id == -1) { + //Get guild_id from the database + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + g = inter_guild_fromsql(guild_id); + if (!g) { + ShowError("Character %d's guild %d not found!\n", char_id, guild_id); + return 0; + } + + //Member has logged in before saving, tell saver not to delete + if (g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; + + //Set member online + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = 1; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + return 1; } int inter_guild_CharOffline(int char_id, int guild_id) { - struct guild *g=NULL; - int online_count, i; - - if (guild_id == -1) - { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - //Character has a guild, set character offline and check if they were the only member online - g = inter_guild_fromsql(guild_id); - if (g == NULL) //Guild not found? - return 0; - - //Set member offline - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 0; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - online_count = 0; - for( i = 0; i < g->max_member; i++ ) - if( g->member[i].online ) - online_count++; - - // Remove guild from memory if no players online - if( online_count == 0 ) - g->save_flag |= GS_REMOVE; - - return 1; + struct guild *g=NULL; + int online_count, i; + + if (guild_id == -1) { + //Get guild_id from the database + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + //Character has a guild, set character offline and check if they were the only member online + g = inter_guild_fromsql(guild_id); + if (g == NULL) //Guild not found? + return 0; + + //Set member offline + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = 0; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + online_count = 0; + for (i = 0; i < g->max_member; i++) + if (g->member[i].online) + online_count++; + + // Remove guild from memory if no players online + if (online_count == 0) + g->save_flag |= GS_REMOVE; + + return 1; } // Initialize guild sql int inter_guild_sql_init(void) { - //Initialize the guild cache - guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - //Read exp file - inter_guild_ReadEXP(); - - add_timer_func_list(guild_save_timer, "guild_save_timer"); - add_timer(gettick() + 10000, guild_save_timer, 0, 0); - return 0; + //Initialize the guild cache + guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); + castle_db = idb_alloc(DB_OPT_RELEASE_DATA); + + //Read exp file + inter_guild_ReadEXP(); + + add_timer_func_list(guild_save_timer, "guild_save_timer"); + add_timer(gettick() + 10000, guild_save_timer, 0, 0); + return 0; } /** @@ -751,145 +751,134 @@ int inter_guild_sql_init(void) */ static int guild_db_final(DBKey key, DBData *data, va_list ap) { - struct guild *g = db_data2ptr(data); - if (g->save_flag&GS_MASK) { - inter_guild_tosql(g, g->save_flag&GS_MASK); - return 1; - } - return 0; + struct guild *g = db_data2ptr(data); + if (g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); + return 1; + } + return 0; } void inter_guild_sql_final(void) { - guild_db_->destroy(guild_db_, guild_db_final); - db_destroy(castle_db); - return; + guild_db_->destroy(guild_db_, guild_db_final); + db_destroy(castle_db); + return; } // Get guild_id by its name. Returns 0 if not found, -1 on error. int search_guildname(char *str) { - int guild_id; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - //Lookup guilds with the same name - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return -1; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - return guild_id; + int guild_id; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + //Lookup guilds with the same name + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -1; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + return guild_id; } // Check if guild is empty static bool guild_check_empty(struct guild *g) { - int i; - ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); - if( i < g->max_member) - return false; // not empty - - //Let the calling function handle the guild removal in case they need - //to do something else with it before freeing the data. [Skotlex] - return true; + int i; + ARR_FIND(0, g->max_member, i, g->member[i].account_id > 0); + if (i < g->max_member) + return false; // not empty + + //Let the calling function handle the guild removal in case they need + //to do something else with it before freeing the data. [Skotlex] + return true; } unsigned int guild_nextexp(int level) { - if (level == 0) - return 1; - if (level < 100 && level > 0) // Change by hack - return guild_exp[level-1]; + if (level == 0) + return 1; + if (level < 100 && level > 0) // Change by hack + return guild_exp[level-1]; - return 0; + return 0; } int guild_checkskill(struct guild *g,int id) { - int idx = id - GD_SKILLBASE; + int idx = id - GD_SKILLBASE; - if(idx < 0 || idx >= MAX_GUILDSKILL) - return 0; + if (idx < 0 || idx >= MAX_GUILDSKILL) + return 0; - return g->skill[idx].lv; + return g->skill[idx].lv; } int guild_calcinfo(struct guild *g) { - int i,c; - unsigned int nextexp; - struct guild before = *g; // Save guild current values - - if(g->guild_lv<=0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - - // Consume guild exp and increase guild level - while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin] - g->exp-=nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } - - // Save next exp step - g->next_exp = nextexp; - - // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; - if(g->max_member > MAX_GUILD) - { - ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - - // Compute the guild average level level - g->average_lv=0; - g->connect_member=0; - for(i=c=0;imax_member;i++) - { - if(g->member[i].account_id>0) - { - if (g->member[i].lv >= 0) - { - g->average_lv+=g->member[i].lv; - c++; - } - else - { - ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); - } - - if(g->member[i].online) - g->connect_member++; - } - } - if(c) - g->average_lv /= c; - - // Check if guild stats has change - if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point ) - { - g->save_flag |= GS_LEVEL; - mapif_guild_info(-1,g); - return 1; - } - - return 0; + int i,c; + unsigned int nextexp; + struct guild before = *g; // Save guild current values + + if (g->guild_lv<=0) + g->guild_lv = 1; + nextexp = guild_nextexp(g->guild_lv); + + // Consume guild exp and increase guild level + while (g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] + g->exp-=nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp(g->guild_lv); + } + + // Save next exp step + g->next_exp = nextexp; + + // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. + g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; + if (g->max_member > MAX_GUILD) { + ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + + // Compute the guild average level level + g->average_lv=0; + g->connect_member=0; + for (i=c=0; imax_member; i++) { + if (g->member[i].account_id>0) { + if (g->member[i].lv >= 0) { + g->average_lv+=g->member[i].lv; + c++; + } else { + ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); + } + + if (g->member[i].online) + g->connect_member++; + } + } + if (c) + g->average_lv /= c; + + // Check if guild stats has change + if (g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point) { + g->save_flag |= GS_LEVEL; + mapif_guild_info(-1,g); + return 1; + } + + return 0; } //------------------------------------------------------------------- @@ -897,245 +886,244 @@ int guild_calcinfo(struct guild *g) int mapif_guild_created(int fd,int account_id,struct guild *g) { - WFIFOHEAD(fd, 10); - WFIFOW(fd,0)=0x3830; - WFIFOL(fd,2)=account_id; - if(g != NULL) - { - WFIFOL(fd,6)=g->guild_id; - ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); - } else - WFIFOL(fd,6)=0; - - WFIFOSET(fd,10); - return 0; + WFIFOHEAD(fd, 10); + WFIFOW(fd,0)=0x3830; + WFIFOL(fd,2)=account_id; + if (g != NULL) { + WFIFOL(fd,6)=g->guild_id; + ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); + } else + WFIFOL(fd,6)=0; + + WFIFOSET(fd,10); + return 0; } // Guild not found int mapif_guild_noinfo(int fd,int guild_id) { - unsigned char buf[12]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=8; - WBUFL(buf,4)=guild_id; - ShowWarning("int_guild: info not found %d\n",guild_id); - if(fd<0) - mapif_sendall(buf,8); - else - mapif_send(fd,buf,8); - return 0; + unsigned char buf[12]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=8; + WBUFL(buf,4)=guild_id; + ShowWarning("int_guild: info not found %d\n",guild_id); + if (fd<0) + mapif_sendall(buf,8); + else + mapif_send(fd,buf,8); + return 0; } // Send guild info int mapif_guild_info(int fd,struct guild *g) { - unsigned char buf[8+sizeof(struct guild)]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=4+sizeof(struct guild); - memcpy(buf+4,g,sizeof(struct guild)); - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); - return 0; + unsigned char buf[8+sizeof(struct guild)]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=4+sizeof(struct guild); + memcpy(buf+4,g,sizeof(struct guild)); + if (fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); + return 0; } // ACK member add int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0)=0x3832; - WFIFOL(fd,2)=guild_id; - WFIFOL(fd,6)=account_id; - WFIFOL(fd,10)=char_id; - WFIFOB(fd,14)=flag; - WFIFOSET(fd,15); - return 0; + WFIFOHEAD(fd, 15); + WFIFOW(fd,0)=0x3832; + WFIFOL(fd,2)=guild_id; + WFIFOL(fd,6)=account_id; + WFIFOL(fd,10)=char_id; + WFIFOB(fd,14)=flag; + WFIFOSET(fd,15); + return 0; } // ACK member leave int mapif_guild_withdraw(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes) { - unsigned char buf[55+NAME_LENGTH]; - WBUFW(buf, 0)=0x3834; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=account_id; - WBUFL(buf,10)=char_id; - WBUFB(buf,14)=flag; - memcpy(WBUFP(buf,15),mes,40); - memcpy(WBUFP(buf,55),name,NAME_LENGTH); - mapif_sendall(buf,55+NAME_LENGTH); - ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); - return 0; + unsigned char buf[55+NAME_LENGTH]; + WBUFW(buf, 0)=0x3834; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=account_id; + WBUFL(buf,10)=char_id; + WBUFB(buf,14)=flag; + memcpy(WBUFP(buf,15),mes,40); + memcpy(WBUFP(buf,55),name,NAME_LENGTH); + mapif_sendall(buf,55+NAME_LENGTH); + ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); + return 0; } // Send short member's info int mapif_guild_memberinfoshort(struct guild *g,int idx) { - unsigned char buf[19]; - WBUFW(buf, 0)=0x3835; - WBUFL(buf, 2)=g->guild_id; - WBUFL(buf, 6)=g->member[idx].account_id; - WBUFL(buf,10)=g->member[idx].char_id; - WBUFB(buf,14)=(unsigned char)g->member[idx].online; - WBUFW(buf,15)=g->member[idx].lv; - WBUFW(buf,17)=g->member[idx].class_; - mapif_sendall(buf,19); - return 0; + unsigned char buf[19]; + WBUFW(buf, 0)=0x3835; + WBUFL(buf, 2)=g->guild_id; + WBUFL(buf, 6)=g->member[idx].account_id; + WBUFL(buf,10)=g->member[idx].char_id; + WBUFB(buf,14)=(unsigned char)g->member[idx].online; + WBUFW(buf,15)=g->member[idx].lv; + WBUFW(buf,17)=g->member[idx].class_; + mapif_sendall(buf,19); + return 0; } // Send guild broken int mapif_guild_broken(int guild_id,int flag) { - unsigned char buf[7]; - WBUFW(buf,0)=0x3836; - WBUFL(buf,2)=guild_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - ShowInfo("int_guild: Guild broken (%d)\n",guild_id); - return 0; + unsigned char buf[7]; + WBUFW(buf,0)=0x3836; + WBUFL(buf,2)=guild_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + ShowInfo("int_guild: Guild broken (%d)\n",guild_id); + return 0; } // Send guild message int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - if (len > 500) - len = 500; - WBUFW(buf,0)=0x3837; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=guild_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + if (len > 500) + len = 500; + WBUFW(buf,0)=0x3837; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=guild_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } // Send basic info int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2038) - len = 2038; - WBUFW(buf, 0)=0x3839; - WBUFW(buf, 2)=len+10; - WBUFL(buf, 4)=guild_id; - WBUFW(buf, 8)=type; - memcpy(WBUFP(buf,10),data,len); - mapif_sendall(buf,len+10); - return 0; + unsigned char buf[2048]; + if (len > 2038) + len = 2038; + WBUFW(buf, 0)=0x3839; + WBUFW(buf, 2)=len+10; + WBUFL(buf, 4)=guild_id; + WBUFW(buf, 8)=type; + memcpy(WBUFP(buf,10),data,len); + mapif_sendall(buf,len+10); + return 0; } // Send member info int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2030) - len = 2030; - WBUFW(buf, 0)=0x383a; - WBUFW(buf, 2)=len+18; - WBUFL(buf, 4)=guild_id; - WBUFL(buf, 8)=account_id; - WBUFL(buf,12)=char_id; - WBUFW(buf,16)=type; - memcpy(WBUFP(buf,18),data,len); - mapif_sendall(buf,len+18); - return 0; + unsigned char buf[2048]; + if (len > 2030) + len = 2030; + WBUFW(buf, 0)=0x383a; + WBUFW(buf, 2)=len+18; + WBUFL(buf, 4)=guild_id; + WBUFL(buf, 8)=account_id; + WBUFL(buf,12)=char_id; + WBUFW(buf,16)=type; + memcpy(WBUFP(buf,18),data,len); + mapif_sendall(buf,len+18); + return 0; } // ACK guild skill up int mapif_guild_skillupack(int guild_id,int skill_num,int account_id) { - unsigned char buf[14]; - WBUFW(buf, 0)=0x383c; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=skill_num; - WBUFL(buf,10)=account_id; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf, 0)=0x383c; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=skill_num; + WBUFL(buf,10)=account_id; + mapif_sendall(buf,14); + return 0; } // ACK guild alliance int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) { - unsigned char buf[19+2*NAME_LENGTH]; - WBUFW(buf, 0)=0x383d; - WBUFL(buf, 2)=guild_id1; - WBUFL(buf, 6)=guild_id2; - WBUFL(buf,10)=account_id1; - WBUFL(buf,14)=account_id2; - WBUFB(buf,18)=flag; - memcpy(WBUFP(buf,19),name1,NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); - mapif_sendall(buf,19+2*NAME_LENGTH); - return 0; + unsigned char buf[19+2*NAME_LENGTH]; + WBUFW(buf, 0)=0x383d; + WBUFL(buf, 2)=guild_id1; + WBUFL(buf, 6)=guild_id2; + WBUFL(buf,10)=account_id1; + WBUFL(buf,14)=account_id2; + WBUFB(buf,18)=flag; + memcpy(WBUFP(buf,19),name1,NAME_LENGTH); + memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); + mapif_sendall(buf,19+2*NAME_LENGTH); + return 0; } // Send a guild position desc int mapif_guild_position(struct guild *g,int idx) { - unsigned char buf[12 + sizeof(struct guild_position)]; - WBUFW(buf,0)=0x383b; - WBUFW(buf,2)=sizeof(struct guild_position)+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=idx; - memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(struct guild_position)]; + WBUFW(buf,0)=0x383b; + WBUFW(buf,2)=sizeof(struct guild_position)+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=idx; + memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } // Send the guild notice int mapif_guild_notice(struct guild *g) { - unsigned char buf[256]; - WBUFW(buf,0)=0x383e; - WBUFL(buf,2)=g->guild_id; - memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); - memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); - mapif_sendall(buf,186); - return 0; + unsigned char buf[256]; + WBUFW(buf,0)=0x383e; + WBUFL(buf,2)=g->guild_id; + memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); + memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); + mapif_sendall(buf,186); + return 0; } // Send emblem data int mapif_guild_emblem(struct guild *g) { - unsigned char buf[12 + sizeof(g->emblem_data)]; - WBUFW(buf,0)=0x383f; - WBUFW(buf,2)=g->emblem_len+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=g->emblem_id; - memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(g->emblem_data)]; + WBUFW(buf,0)=0x383f; + WBUFW(buf,2)=g->emblem_len+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=g->emblem_id; + memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } int mapif_guild_master_changed(struct guild *g, int aid, int cid) { - unsigned char buf[14]; - WBUFW(buf,0)=0x3843; - WBUFL(buf,2)=g->guild_id; - WBUFL(buf,6)=aid; - WBUFL(buf,10)=cid; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf,0)=0x3843; + WBUFL(buf,2)=g->guild_id; + WBUFL(buf,6)=aid; + WBUFL(buf,10)=cid; + mapif_sendall(buf,14); + return 0; } int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) { - struct guild_castle *gc = NULL; - int num = (sz - 4) / sizeof(int); - int len = 4 + num * sizeof(*gc); - int i; - - WFIFOHEAD(fd, len); - WFIFOW(fd, 0) = 0x3840; - WFIFOW(fd, 2) = len; - for (i = 0; i < num; i++) { - gc = inter_guildcastle_fromsql(*(castle_ids++)); - memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); - } - WFIFOSET(fd, len); - return 0; + struct guild_castle *gc = NULL; + int num = (sz - 4) / sizeof(int); + int len = 4 + num * sizeof(*gc); + int i; + + WFIFOHEAD(fd, len); + WFIFOW(fd, 0) = 0x3840; + WFIFOW(fd, 2) = len; + for (i = 0; i < num; i++) { + gc = inter_guildcastle_fromsql(*(castle_ids++)); + memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); + } + WFIFOSET(fd, len); + return 0; } //------------------------------------------------------------------- @@ -1145,696 +1133,680 @@ int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) // Guild creation request int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master) { - struct guild *g; - int i=0; + struct guild *g; + int i=0; #ifdef NOISY - ShowInfo("Creating Guild (%s)\n", name); + ShowInfo("Creating Guild (%s)\n", name); #endif - if(search_guildname(name) != 0){ - ShowInfo("int_guild: guild with same name exists [%s]\n",name); - mapif_guild_created(fd,account_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } - - g = (struct guild *)aMalloc(sizeof(struct guild)); - memset(g,0,sizeof(struct guild)); - - memcpy(g->name,name,NAME_LENGTH); - memcpy(g->master,master->name,NAME_LENGTH); - memcpy(&g->member[0],master,sizeof(struct guild_member)); - g->member[0].modified = GS_MEMBER_MODIFIED; - - // Set default positions - g->position[0].mode=0x11; - strcpy(g->position[0].name,"GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); - g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; - for(i=1;iposition[i].name,"Position %d",i+1); - g->position[i].modified = GS_POSITION_MODIFIED; - } - - // Initialize guild property - g->max_member=16; - g->average_lv=master->lv; - g->connect_member=1; - - for(i=0;iskill[i].id=i + GD_SKILLBASE; - g->guild_id= -1; //Request to create guild. - - // Create the guild - if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { - //Failed to Create guild.... - ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); - mapif_guild_created(fd,account_id,NULL); - aFree(g); - return 0; - } - ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); - - //Add to cache - idb_put(guild_db_, g->guild_id, g); - - // Report to client - mapif_guild_created(fd,account_id,g); - mapif_guild_info(fd,g); - - if(log_inter) - inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id ); - - return 0; + if (search_guildname(name) != 0) { + ShowInfo("int_guild: guild with same name exists [%s]\n",name); + mapif_guild_created(fd,account_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } + + g = (struct guild *)aMalloc(sizeof(struct guild)); + memset(g,0,sizeof(struct guild)); + + memcpy(g->name,name,NAME_LENGTH); + memcpy(g->master,master->name,NAME_LENGTH); + memcpy(&g->member[0],master,sizeof(struct guild_member)); + g->member[0].modified = GS_MEMBER_MODIFIED; + + // Set default positions + g->position[0].mode=0x11; + strcpy(g->position[0].name,"GuildMaster"); + strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); + g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; + for (i=1; iposition[i].name,"Position %d",i+1); + g->position[i].modified = GS_POSITION_MODIFIED; + } + + // Initialize guild property + g->max_member=16; + g->average_lv=master->lv; + g->connect_member=1; + + for (i=0; iskill[i].id=i + GD_SKILLBASE; + g->guild_id= -1; //Request to create guild. + + // Create the guild + if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { + //Failed to Create guild.... + ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); + mapif_guild_created(fd,account_id,NULL); + aFree(g); + return 0; + } + ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); + + //Add to cache + idb_put(guild_db_, g->guild_id, g); + + // Report to client + mapif_guild_created(fd,account_id,g); + mapif_guild_info(fd,g); + + if (log_inter) + inter_log("guild %s (id=%d) created by master %s (id=%d)\n", + name, g->guild_id, master->name, master->account_id); + + return 0; } // Return guild info to client int mapif_parse_GuildInfo(int fd,int guild_id) { - struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] - if(g) - { - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - } - else - mapif_guild_noinfo(fd,guild_id); // Failed to load info - return 0; + struct guild *g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] + if (g) { + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + } else + mapif_guild_noinfo(fd,guild_id); // Failed to load info + return 0; } // Add member to guild int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m) { - struct guild * g; - int i; - - g = inter_guild_fromsql(guild_id); - if(g==NULL){ - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; - } - - // Find an empty slot - for(i=0;imax_member;i++) - { - if(g->member[i].account_id==0) - { - memcpy(&g->member[i],m,sizeof(struct guild_member)); - g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); - if (!guild_calcinfo(g)) //Send members if it was not invoked. - mapif_guild_info(-1,g); - - g->save_flag |= GS_MEMBER; - if (g->save_flag&GS_REMOVE) - g->save_flag&=~GS_REMOVE; - return 0; - } - } - - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; + struct guild *g; + int i; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) { + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; + } + + // Find an empty slot + for (i=0; imax_member; i++) { + if (g->member[i].account_id==0) { + memcpy(&g->member[i],m,sizeof(struct guild_member)); + g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); + if (!guild_calcinfo(g)) //Send members if it was not invoked. + mapif_guild_info(-1,g); + + g->save_flag |= GS_MEMBER; + if (g->save_flag&GS_REMOVE) + g->save_flag&=~GS_REMOVE; + return 0; + } + } + + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; } // Delete member from guild int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) { - int i, j; - - struct guild* g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - // Unknown guild, just update the player - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - return 0; - } - - // Find the member - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i == g->max_member ) - { - //TODO - return 0; - } - - if( flag ) - { // Write expulsion reason - // Find an empty slot - ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if( j == MAX_GUILDEXPULSION ) - { - // Expulsion list is full, flush the oldest one - for( j = 0; j < MAX_GUILDEXPULSION - 1; j++ ) - g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION-1; - } - // Save the expulsion entry - g->expulsion[j].account_id = account_id; - safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); - safestrncpy(g->expulsion[j].mes, mes, 40); - } - - mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); - - memset(&g->member[i],0,sizeof(struct guild_member)); - - if( guild_check_empty(g) ) - mapif_parse_BreakGuild(-1,guild_id); //Break the guild. - else { - //Update member info. - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - g->save_flag |= GS_EXPULSION; - } - - return 0; + int i, j; + + struct guild *g = inter_guild_fromsql(guild_id); + if (g == NULL) { + // Unknown guild, just update the player + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); + // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + return 0; + } + + // Find the member + ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); + if (i == g->max_member) { + //TODO + return 0; + } + + if (flag) { + // Write expulsion reason + // Find an empty slot + ARR_FIND(0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0); + if (j == MAX_GUILDEXPULSION) { + // Expulsion list is full, flush the oldest one + for (j = 0; j < MAX_GUILDEXPULSION - 1; j++) + g->expulsion[j] = g->expulsion[j+1]; + j = MAX_GUILDEXPULSION-1; + } + // Save the expulsion entry + g->expulsion[j].account_id = account_id; + safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); + safestrncpy(g->expulsion[j].mes, mes, 40); + } + + mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); + + memset(&g->member[i],0,sizeof(struct guild_member)); + + if (guild_check_empty(g)) + mapif_parse_BreakGuild(-1,guild_id); //Break the guild. + else { + //Update member info. + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + g->save_flag |= GS_EXPULSION; + } + + return 0; } // Change member info int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,int account_id,int char_id,int online,int lv,int class_) { - // Could speed up by manipulating only guild_member - struct guild * g; - int i,sum,c; - int prev_count, prev_alv; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfoshort(g,i); - } - - prev_count = g->connect_member; - prev_alv = g->average_lv; - - g->average_lv = 0; - g->connect_member = 0; - c = 0; - sum = 0; - - for( i = 0; i < g->max_member; i++ ) - { - if( g->member[i].account_id > 0 ) - { - sum += g->member[i].lv; - c++; - } - if( g->member[i].online ) - g->connect_member++; - } - - if( c ) // this check should always succeed... - { - g->average_lv = sum / c; - if( g->connect_member != prev_count || g->average_lv != prev_alv ) - g->save_flag |= GS_CONNECT; - if( g->save_flag & GS_REMOVE ) - g->save_flag &= ~GS_REMOVE; - } - g->save_flag |= GS_MEMBER; //Update guild member data - return 0; + // Could speed up by manipulating only guild_member + struct guild *g; + int i,sum,c; + int prev_count, prev_alv; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].class_ = class_; + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfoshort(g,i); + } + + prev_count = g->connect_member; + prev_alv = g->average_lv; + + g->average_lv = 0; + g->connect_member = 0; + c = 0; + sum = 0; + + for (i = 0; i < g->max_member; i++) { + if (g->member[i].account_id > 0) { + sum += g->member[i].lv; + c++; + } + if (g->member[i].online) + g->connect_member++; + } + + if (c) { // this check should always succeed... + g->average_lv = sum / c; + if (g->connect_member != prev_count || g->average_lv != prev_alv) + g->save_flag |= GS_CONNECT; + if (g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; + } + g->save_flag |= GS_MEMBER; //Update guild member data + return 0; } // BreakGuild int mapif_parse_BreakGuild(int fd,int guild_id) { - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + struct guild *g; - // Delete guild from sql - //printf("- Delete guild %d from guild\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) - Sql_ShowDebug(sql_handle); + // Delete guild from sql + //printf("- Delete guild %d from guild\n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id)) + Sql_ShowDebug(sql_handle); - //printf("- Update guild %d of char\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id)) + Sql_ShowDebug(sql_handle); - mapif_guild_broken(guild_id,0); + //printf("- Update guild %d of char\n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id)) + Sql_ShowDebug(sql_handle); - if(log_inter) - inter_log("guild %s (id=%d) broken\n",g->name,guild_id); + mapif_guild_broken(guild_id,0); - //Remove the guild from memory. [Skotlex] - idb_remove(guild_db_, guild_id); - return 0; + if (log_inter) + inter_log("guild %s (id=%d) broken\n",g->name,guild_id); + + //Remove the guild from memory. [Skotlex] + idb_remove(guild_db_, guild_id); + return 0; } // Forward Guild message to others map servers int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len) { - return mapif_guild_message(guild_id,account_id,mes,len, fd); + return mapif_guild_message(guild_id,account_id,mes,len, fd); } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len) { - struct guild * g; - short dw=*((short *)data); - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - switch(type) - { - case GBI_GUILDLV: - if(dw>0 && g->guild_lv+dw<=50) - { - g->guild_lv+=dw; - g->skill_point+=dw; - } - else if(dw<0 && g->guild_lv+dw>=1) - g->guild_lv+=dw; - mapif_guild_info(-1,g); - g->save_flag |= GS_LEVEL; - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); - break; - } - mapif_guild_basicinfochanged(guild_id,type,data,len); - return 0; + struct guild *g; + short dw=*((short *)data); + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + switch (type) { + case GBI_GUILDLV: + if (dw>0 && g->guild_lv+dw<=50) { + g->guild_lv+=dw; + g->skill_point+=dw; + } else if (dw<0 && g->guild_lv+dw>=1) + g->guild_lv+=dw; + mapif_guild_info(-1,g); + g->save_flag |= GS_LEVEL; + return 0; + default: + ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); + break; + } + mapif_guild_basicinfochanged(guild_id,type,data,len); + return 0; } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,int type,const char *data,int len) { - // Could make some improvement in speed, because only change guild_member - int i; - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - // Search the member - for(i=0;imax_member;i++) - if( g->member[i].account_id==account_id && - g->member[i].char_id==char_id ) - break; - - // Not Found - if(i==g->max_member){ - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", - account_id,char_id,guild_id,g->name); - return 0; - } - - switch(type) - { - case GMI_POSITION: - { - g->member[i].position=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_EXP: - { // EXP - uint64 exp, old_exp=g->member[i].exp; - g->member[i].exp=*((uint64 *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - if (g->member[i].exp > old_exp) - { - exp = g->member[i].exp - old_exp; - - // Compute gained exp - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - - // Update guild exp - if (exp > UINT64_MAX - g->exp) - g->exp = UINT64_MAX; - else - g->exp+=exp; - - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); - g->save_flag |= GS_LEVEL; - } - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_GENDER: - { - g->member[i].gender=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_CLASS: - { - g->member[i].class_=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_LEVEL: - { - g->member[i].lv=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); - break; - } - return 0; + // Could make some improvement in speed, because only change guild_member + int i; + struct guild *g; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + // Search the member + for (i=0; imax_member; i++) + if (g->member[i].account_id==account_id && + g->member[i].char_id==char_id) + break; + + // Not Found + if (i==g->max_member) { + ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", + account_id,char_id,guild_id,g->name); + return 0; + } + + switch (type) { + case GMI_POSITION: { + g->member[i].position=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_EXP: { + // EXP + uint64 exp, old_exp=g->member[i].exp; + g->member[i].exp=*((uint64 *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + if (g->member[i].exp > old_exp) { + exp = g->member[i].exp - old_exp; + + // Compute gained exp + if (guild_exp_rate != 100) + exp = exp*guild_exp_rate/100; + + // Update guild exp + if (exp > UINT64_MAX - g->exp) + g->exp = UINT64_MAX; + else + g->exp+=exp; + + guild_calcinfo(g); + mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); + g->save_flag |= GS_LEVEL; + } + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_HAIR: { + g->member[i].hair=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_HAIR_COLOR: { + g->member[i].hair_color=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_GENDER: { + g->member[i].gender=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_CLASS: { + g->member[i].class_=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_LEVEL: { + g->member[i].lv=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + default: + ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); + break; + } + return 0; } int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) { - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); + return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char *)&gender, sizeof(gender)); } int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name) { - struct guild *g; - int i, flag = 0; - - g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); - return 0; - } - - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if( i == g->max_member ) - { - ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); - return 0; - } - - if( !strcmp(g->member[i].name, g->master) ) - { - safestrncpy(g->master, name, NAME_LENGTH); - flag |= GS_BASIC; - } - safestrncpy(g->member[i].name, name, NAME_LENGTH); - g->member[i].modified = GS_MEMBER_MODIFIED; - flag |= GS_MEMBER; - - if( !inter_guild_tosql(g, flag) ) - return 0; - - mapif_guild_info(-1,g); - - return 0; + struct guild *g; + int i, flag = 0; + + g = inter_guild_fromsql(guild_id); + if (g == NULL) { + ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); + return 0; + } + + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i == g->max_member) { + ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); + return 0; + } + + if (!strcmp(g->member[i].name, g->master)) { + safestrncpy(g->master, name, NAME_LENGTH); + flag |= GS_BASIC; + } + safestrncpy(g->member[i].name, name, NAME_LENGTH); + g->member[i].modified = GS_MEMBER_MODIFIED; + flag |= GS_MEMBER; + + if (!inter_guild_tosql(g, flag)) + return 0; + + mapif_guild_info(-1,g); + + return 0; } // Change a position desc int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p) { - // Could make some improvement in speed, because only change guild_position - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) - return 0; - - memcpy(&g->position[idx],p,sizeof(struct guild_position)); - mapif_guild_position(g,idx); - g->position[idx].modified = GS_POSITION_MODIFIED; - g->save_flag |= GS_POSITION; // Change guild_position - return 0; + // Could make some improvement in speed, because only change guild_position + struct guild *g; + + g = inter_guild_fromsql(guild_id); + if (g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) + return 0; + + memcpy(&g->position[idx],p,sizeof(struct guild_position)); + mapif_guild_position(g,idx); + g->position[idx].modified = GS_POSITION_MODIFIED; + g->save_flag |= GS_POSITION; // Change guild_position + return 0; } // Guild Skill UP int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id,int max) { - struct guild * g; - int idx = skill_num - GD_SKILLBASE; - - g = inter_guild_fromsql(guild_id); - if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; - g->skill_point--; - if (!guild_calcinfo(g)) - mapif_guild_info(-1,g); - mapif_guild_skillupack(guild_id,skill_num,account_id); - g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill - } - return 0; + struct guild *g; + int idx = skill_num - GD_SKILLBASE; + + g = inter_guild_fromsql(guild_id); + if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + + if (g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; + g->skill_point--; + if (!guild_calcinfo(g)) + mapif_guild_info(-1,g); + mapif_guild_skillupack(guild_id,skill_num,account_id); + g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill + } + return 0; } //Manual deletion of an alliance when partnering guild does not exists. [Skotlex] static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) { - int i; - char name[NAME_LENGTH]; - - ARR_FIND( 0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id ); - if( i == MAX_GUILDALLIANCE ) - return -1; - - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - g->save_flag |= GS_ALLIANCE; - return 0; + int i; + char name[NAME_LENGTH]; + + ARR_FIND(0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id); + if (i == MAX_GUILDALLIANCE) + return -1; + + strcpy(name, g->alliance[i].name); + g->alliance[i].guild_id=0; + + mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); + g->save_flag |= GS_ALLIANCE; + return 0; } // Alliance modification int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) { - // Could speed up - struct guild *g[2]; - int j,i; - g[0] = inter_guild_fromsql(guild_id1); - g[1] = inter_guild_fromsql(guild_id2); - - if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if(g[0]==NULL || g[1]==NULL) - return 0; - - if(flag&GUILD_ALLIANCE_REMOVE) - { - // Remove alliance/opposition, in case of alliance, remove on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK) ); - if( j < MAX_GUILDALLIANCE ) - g[i]->alliance[j].guild_id = 0; - } - } - else - { - // Add alliance, in case of alliance, add on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - // Search an empty slot - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); - if( j < MAX_GUILDALLIANCE ) - { - g[i]->alliance[j].guild_id=g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); - // Set alliance type - g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; - } - } - } - - // Send on all map the new alliance/opposition - mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); - - // Mark the two guild to be saved - g[0]->save_flag |= GS_ALLIANCE; - g[1]->save_flag |= GS_ALLIANCE; - return 0; + // Could speed up + struct guild *g[2]; + int j,i; + g[0] = inter_guild_fromsql(guild_id1); + g[1] = inter_guild_fromsql(guild_id2); + + if (g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. + return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. + + if (g[0]==NULL || g[1]==NULL) + return 0; + + if (flag&GUILD_ALLIANCE_REMOVE) { + // Remove alliance/opposition, in case of alliance, remove on both side + for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { + ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK)); + if (j < MAX_GUILDALLIANCE) + g[i]->alliance[j].guild_id = 0; + } + } else { + // Add alliance, in case of alliance, add on both side + for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { + // Search an empty slot + ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0); + if (j < MAX_GUILDALLIANCE) { + g[i]->alliance[j].guild_id=g[1-i]->guild_id; + memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); + // Set alliance type + g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; + } + } + } + + // Send on all map the new alliance/opposition + mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); + + // Mark the two guild to be saved + g[0]->save_flag |= GS_ALLIANCE; + g[1]->save_flag |= GS_ALLIANCE; + return 0; } // Change guild message int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2) { - struct guild *g; + struct guild *g; - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - memcpy(g->mes1,mes1,MAX_GUILDMES1); - memcpy(g->mes2,mes2,MAX_GUILDMES2); - g->save_flag |= GS_MES; //Change mes of guild - return mapif_guild_notice(g); + memcpy(g->mes1,mes1,MAX_GUILDMES1); + memcpy(g->mes2,mes2,MAX_GUILDMES2); + g->save_flag |= GS_MES; //Change mes of guild + return mapif_guild_notice(g); } int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data) { - struct guild * g; + struct guild *g; - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - if (len > sizeof(g->emblem_data)) - len = sizeof(g->emblem_data); + if (len > sizeof(g->emblem_data)) + len = sizeof(g->emblem_data); - memcpy(g->emblem_data,data,len); - g->emblem_len=len; - g->emblem_id++; - g->save_flag |= GS_EMBLEM; //Change guild - return mapif_guild_emblem(g); + memcpy(g->emblem_data,data,len); + g->emblem_len=len; + g->emblem_id++; + g->save_flag |= GS_EMBLEM; //Change guild + return mapif_guild_emblem(g); } int mapif_parse_GuildCastleDataLoad(int fd, int len, int *castle_ids) { - return mapif_guild_castle_dataload(fd, len, castle_ids); + return mapif_guild_castle_dataload(fd, len, castle_ids); } int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) { - struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); - - if (gc == NULL) { - ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); - return 0; - } - - switch (index) { - case 1: - if (log_inter && gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = idb_get(guild_db_, gid); - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); - } - gc->guild_id = value; - break; - case 2: gc->economy = value; break; - case 3: gc->defense = value; break; - case 4: gc->triggerE = value; break; - case 5: gc->triggerD = value; break; - case 6: gc->nextTime = value; break; - case 7: gc->payTime = value; break; - case 8: gc->createTime = value; break; - case 9: gc->visibleC = value; break; - default: - if (index > 9 && index <= 9+MAX_GUARDIANS) { - gc->guardian[index-10].visible = value; - break; - } - ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); - return 0; - } - inter_guildcastle_tosql(gc); - return 0; + struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); + + if (gc == NULL) { + ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); + return 0; + } + + switch (index) { + case 1: + if (log_inter && gc->guild_id != value) { + int gid = (value) ? value : gc->guild_id; + struct guild *g = idb_get(guild_db_, gid); + inter_log("guild %s (id=%d) %s castle id=%d\n", + (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); + } + gc->guild_id = value; + break; + case 2: + gc->economy = value; + break; + case 3: + gc->defense = value; + break; + case 4: + gc->triggerE = value; + break; + case 5: + gc->triggerD = value; + break; + case 6: + gc->nextTime = value; + break; + case 7: + gc->payTime = value; + break; + case 8: + gc->createTime = value; + break; + case 9: + gc->visibleC = value; + break; + default: + if (index > 9 && index <= 9+MAX_GUARDIANS) { + gc->guardian[index-10].visible = value; + break; + } + ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); + return 0; + } + inter_guildcastle_tosql(gc); + return 0; } -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) +int mapif_parse_GuildMasterChange(int fd, int guild_id, const char *name, int len) { - struct guild * g; - struct guild_member gm; - int pos; - - g = inter_guild_fromsql(guild_id); - - if(g==NULL || len > NAME_LENGTH) - return 0; - - // Find member (name) - for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); - - if (pos == g->max_member) - return 0; //Character not found?? - - // Switch current and old GM - memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); - memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); - memcpy(&g->member[0], &gm, sizeof(struct guild_member)); - - // Switch positions - g->member[pos].position = g->member[0].position; - g->member[pos].modified = GS_MEMBER_MODIFIED; - g->member[0].position = 0; //Position 0: guild Master. - g->member[0].modified = GS_MEMBER_MODIFIED; - - strncpy(g->master, name, len); - if (len < NAME_LENGTH) - g->master[len] = '\0'; - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); - g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); + struct guild *g; + struct guild_member gm; + int pos; + + g = inter_guild_fromsql(guild_id); + + if (g==NULL || len > NAME_LENGTH) + return 0; + + // Find member (name) + for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); + + if (pos == g->max_member) + return 0; //Character not found?? + + // Switch current and old GM + memcpy(&gm, &g->member[pos], sizeof(struct guild_member)); + memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); + memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + + // Switch positions + g->member[pos].position = g->member[0].position; + g->member[pos].modified = GS_MEMBER_MODIFIED; + g->member[0].position = 0; //Position 0: guild Master. + g->member[0].modified = GS_MEMBER_MODIFIED; + + strncpy(g->master, name, len); + if (len < NAME_LENGTH) + g->master[len] = '\0'; + + ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); + g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. + return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); } // Communication from the map server @@ -1842,44 +1814,78 @@ int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int le // Data packet length that you set to inter.c //- Shouldn't do checking and packet length, RFIFOSKIP is done by the caller // Must Return -// 1 : ok +// 1 : ok // 0 : error int inter_guild_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break; - case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break; - case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break; - case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; - case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break; - case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break; - case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break; - case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; - case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break; - case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break; - case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break; - case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); break; - case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break; - case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break; - case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break; - case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break; - - default: - return 0; - } - - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3030: + mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char *)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); + break; + case 0x3031: + mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); + break; + case 0x3032: + mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); + break; + case 0x3033: + mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char *)RFIFOP(fd,8),RFIFOW(fd,2)-8); + break; + case 0x3034: + mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char *)RFIFOP(fd,15)); + break; + case 0x3035: + mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); + break; + case 0x3036: + mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); + break; + case 0x3037: + mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char *)RFIFOP(fd,12),RFIFOW(fd,2)-12); + break; + case 0x3039: + mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char *)RFIFOP(fd,10),RFIFOW(fd,2)-10); + break; + case 0x303A: + mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char *)RFIFOP(fd,18),RFIFOW(fd,2)-18); + break; + case 0x303B: + mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); + break; + case 0x303C: + mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); + break; + case 0x303D: + mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); + break; + case 0x303E: + mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char *)RFIFOP(fd,6),(const char *)RFIFOP(fd,66)); + break; + case 0x303F: + mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char *)RFIFOP(fd,12)); + break; + case 0x3040: + mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); + break; + case 0x3041: + mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); + break; + + default: + return 0; + } + + return 1; } //Leave request from the server (for deleting character from guild) int inter_guild_leave(int guild_id, int account_id, int char_id) { - return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); + return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); } int inter_guild_broken(int guild_id) { - return mapif_guild_broken(guild_id, 0); + return mapif_guild_broken(guild_id, 0); } diff --git a/src/char/int_guild.h b/src/char/int_guild.h index 47c42dcc5..5bc3c2fe3 100644 --- a/src/char/int_guild.h +++ b/src/char/int_guild.h @@ -5,19 +5,19 @@ #define _INT_GUILD_SQL_H_ enum { - GS_BASIC = 0x0001, - GS_MEMBER = 0x0002, - GS_POSITION = 0x0004, - GS_ALLIANCE = 0x0008, - GS_EXPULSION = 0x0010, - GS_SKILL = 0x0020, - GS_EMBLEM = 0x0040, - GS_CONNECT = 0x0080, - GS_LEVEL = 0x0100, - GS_MES = 0x0200, - GS_MASK = 0x03FF, - GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), - GS_REMOVE = 0x8000, + GS_BASIC = 0x0001, + GS_MEMBER = 0x0002, + GS_POSITION = 0x0004, + GS_ALLIANCE = 0x0008, + GS_EXPULSION = 0x0010, + GS_SKILL = 0x0020, + GS_EMBLEM = 0x0040, + GS_CONNECT = 0x0080, + GS_LEVEL = 0x0100, + GS_MES = 0x0200, + GS_MASK = 0x03FF, + GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), + GS_REMOVE = 0x8000, }; struct guild; diff --git a/src/char/int_homun.c b/src/char/int_homun.c index 933661954..5676556f4 100644 --- a/src/char/int_homun.c +++ b/src/char/int_homun.c @@ -18,279 +18,281 @@ int inter_homunculus_sql_init(void) { - return 0; + return 0; } void inter_homunculus_sql_final(void) { - return; + return; } static void mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3890; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= flag; - memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3890; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + WFIFOB(fd,8)= flag; + memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); + WFIFOSET(fd, WFIFOW(fd,2)); } static void mapif_homunculus_deleted(int fd, int flag) { - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) = 0x3893; - WFIFOB(fd,2) = flag; //Flag 1 = success - WFIFOSET(fd, 3); + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) = 0x3893; + WFIFOB(fd,2) = flag; //Flag 1 = success + WFIFOSET(fd, 3); } static void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - if( hd != NULL ) - { - WFIFOB(fd,8) = 1; // success - memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); - } - else - { - WFIFOB(fd,8) = 0; // not found. - memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); - } - WFIFOSET(fd, sizeof(struct s_homunculus)+9); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3891; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + if (hd != NULL) { + WFIFOB(fd,8) = 1; // success + memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); + } else { + WFIFOB(fd,8) = 0; // not found. + memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); + } + WFIFOSET(fd, sizeof(struct s_homunculus)+9); } static void mapif_homunculus_saved(int fd, int account_id, bool flag) { - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x3892; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = flag; // 1:success, 0:failure - WFIFOSET(fd, 7); + WFIFOHEAD(fd, 7); + WFIFOW(fd,0) = 0x3892; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = flag; // 1:success, 0:failure + WFIFOSET(fd, 7); } -static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char* name) +static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char *name) { - WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) = 0x3894; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = flag; - safestrncpy((char*)WFIFOP(fd,11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); + WFIFOHEAD(fd, NAME_LENGTH+12); + WFIFOW(fd, 0) = 0x3894; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = flag; + safestrncpy((char *)WFIFOP(fd,11), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+12); } -bool mapif_homunculus_save(struct s_homunculus* hd) +bool mapif_homunculus_save(struct s_homunculus *hd) { - bool flag = true; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); - - if( hd->hom_id == 0 ) - {// new homunculus - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " - "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - hd->hom_id = (int)Sql_LastInsertId(sql_handle); - } - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - SqlStmt* stmt; - int i; - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_HOMUNSKILL; ++i ) - { - if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 ) - { - SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); - SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); - if( SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - flag = false; - break; - } - } - } - SqlStmt_Free(stmt); - } - } - - return flag; + bool flag = true; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); + + if (hd->hom_id == 0) { + // new homunculus + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " + "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else { + hd->hom_id = (int)Sql_LastInsertId(sql_handle); + } + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else { + SqlStmt *stmt; + int i; + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_HOMUNSKILL; ++i) { + if (hd->hskill[i].id > 0 && hd->hskill[i].lv != 0) { + SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); + SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); + if (SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + flag = false; + break; + } + } + } + SqlStmt_Free(stmt); + } + } + + return flag; } // Load an homunculus -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd) +bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd) { - int i; - char* data; - size_t len; - - memset(hd, 0, sizeof(*hd)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( !Sql_NumRows(sql_handle) ) - { //No homunculus found. - Sql_FreeResult(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - hd->hom_id = homun_id; - Sql_GetData(sql_handle, 1, &data, NULL); hd->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); hd->class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); hd->prev_class = atoi(data); - Sql_GetData(sql_handle, 4, &data, &len); safestrncpy(hd->name, data, sizeof(hd->name)); - Sql_GetData(sql_handle, 5, &data, NULL); hd->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); hd->exp = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); hd->intimacy = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); hd->hunger = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); hd->str = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); hd->agi = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); hd->vit = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); hd->int_ = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); hd->dex = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); hd->luk = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); hd->hp = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); hd->max_hp = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); hd->sp = atoi(data); - Sql_GetData(sql_handle, 18, &data, NULL); hd->max_sp = atoi(data); - Sql_GetData(sql_handle, 19, &data, NULL); hd->skillpts = atoi(data); - Sql_GetData(sql_handle, 20, &data, NULL); hd->rename_flag = atoi(data); - Sql_GetData(sql_handle, 21, &data, NULL); hd->vaporize = atoi(data); - Sql_FreeResult(sql_handle); - - hd->intimacy = cap_value(hd->intimacy, 0, 100000); - hd->hunger = cap_value(hd->hunger, 0, 100); - - // Load Homunculus Skill - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - // id - Sql_GetData(sql_handle, 0, &data, NULL); - i = atoi(data); - if( i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL ) - continue;// invalid skill id - i = i - HM_SKILLBASE; - hd->hskill[i].id = (unsigned short)atoi(data); - - // lv - Sql_GetData(sql_handle, 1, &data, NULL); - hd->hskill[i].lv = (unsigned char)atoi(data); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); - - return true; + int i; + char *data; + size_t len; + + memset(hd, 0, sizeof(*hd)); + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (!Sql_NumRows(sql_handle)) { + //No homunculus found. + Sql_FreeResult(sql_handle); + return false; + } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + hd->hom_id = homun_id; + Sql_GetData(sql_handle, 1, &data, NULL); + hd->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + hd->class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + hd->prev_class = atoi(data); + Sql_GetData(sql_handle, 4, &data, &len); + safestrncpy(hd->name, data, sizeof(hd->name)); + Sql_GetData(sql_handle, 5, &data, NULL); + hd->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + hd->exp = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + hd->intimacy = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + hd->hunger = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + hd->str = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + hd->agi = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + hd->vit = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); + hd->int_ = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); + hd->dex = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); + hd->luk = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); + hd->hp = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); + hd->max_hp = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); + hd->sp = atoi(data); + Sql_GetData(sql_handle, 18, &data, NULL); + hd->max_sp = atoi(data); + Sql_GetData(sql_handle, 19, &data, NULL); + hd->skillpts = atoi(data); + Sql_GetData(sql_handle, 20, &data, NULL); + hd->rename_flag = atoi(data); + Sql_GetData(sql_handle, 21, &data, NULL); + hd->vaporize = atoi(data); + Sql_FreeResult(sql_handle); + + hd->intimacy = cap_value(hd->intimacy, 0, 100000); + hd->hunger = cap_value(hd->hunger, 0, 100); + + // Load Homunculus Skill + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + // id + Sql_GetData(sql_handle, 0, &data, NULL); + i = atoi(data); + if (i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL) + continue;// invalid skill id + i = i - HM_SKILLBASE; + hd->hskill[i].id = (unsigned short)atoi(data); + + // lv + Sql_GetData(sql_handle, 1, &data, NULL); + hd->hskill[i].lv = (unsigned char)atoi(data); + } + Sql_FreeResult(sql_handle); + + if (save_log) + ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); + + return true; } bool mapif_homunculus_delete(int homun_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) - || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - return true; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) + || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + return true; } bool mapif_homunculus_rename(char *name) { - int i; - - // Check Authorised letters/symbols in the name of the homun - if( char_name_option == 1 ) - {// only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return false; - } else - if( char_name_option == 2 ) - {// letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return false; - } - - return true; + int i; + + // Check Authorised letters/symbols in the name of the homun + if (char_name_option == 1) { + // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) + return false; + } else if (char_name_option == 2) { + // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) + return false; + } + + return true; } -static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus* phd) +static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus *phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_created(fd, account_id, phd, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_created(fd, account_id, phd, result); } static void mapif_parse_homunculus_delete(int fd, int homun_id) { - bool result = mapif_homunculus_delete(homun_id); - mapif_homunculus_deleted(fd, result); + bool result = mapif_homunculus_delete(homun_id); + mapif_homunculus_deleted(fd, result); } static void mapif_parse_homunculus_load(int fd, int account_id, int homun_id) { - struct s_homunculus hd; - bool result = mapif_homunculus_load(homun_id, &hd); - mapif_homunculus_loaded(fd, account_id, ( result ? &hd : NULL )); + struct s_homunculus hd; + bool result = mapif_homunculus_load(homun_id, &hd); + mapif_homunculus_loaded(fd, account_id, (result ? &hd : NULL)); } -static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus* phd) +static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus *phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_saved(fd, account_id, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_saved(fd, account_id, result); } -static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char* name) +static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char *name) { - bool result = mapif_homunculus_rename(name); - mapif_homunculus_renamed(fd, account_id, char_id, result, name); + bool result = mapif_homunculus_rename(name); + mapif_homunculus_renamed(fd, account_id, char_id, result, name); } /*========================================== @@ -298,17 +300,26 @@ static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, c *------------------------------------------*/ int inter_homunculus_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x3090: + mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); + break; + case 0x3091: + mapif_parse_homunculus_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x3092: + mapif_parse_homunculus_save(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); + break; + case 0x3093: + mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x3094: + mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char *)RFIFOP(fd,10)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_homun.h b/src/char/int_homun.h index 1c0d76269..e7976d51a 100644 --- a/src/char/int_homun.h +++ b/src/char/int_homun.h @@ -10,8 +10,8 @@ int inter_homunculus_sql_init(void); void inter_homunculus_sql_final(void); int inter_homunculus_parse_frommap(int fd); -bool mapif_homunculus_save(struct s_homunculus* hd); -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd); +bool mapif_homunculus_save(struct s_homunculus *hd); +bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd); bool mapif_homunculus_delete(int homun_id); bool mapif_homunculus_rename(char *name); diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 98da43aeb..2e34d9014 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -15,180 +15,200 @@ #include #include -static int mail_fromsql(int char_id, struct mail_data* md) +static int mail_fromsql(int char_id, struct mail_data *md) { - int i, j; - struct mail_message *msg; - struct item *item; - char *data; - StringBuf buf; - - memset(md, 0, sizeof(struct mail_data)); - md->amount = 0; - md->full = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ",`card%d`", i); - - // I keep the `status` < 3 just in case someone forget to apply the sqlfix - StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", - mail_db, char_id, MAIL_MAX_INBOX + 1); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - msg = &md->msg[i]; - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - item = &msg->item; - Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); - item->expire_time = 0; - - for (j = 0; j < MAX_SLOTS; j++) - { - Sql_GetData(sql_handle, 15 + j, &data, NULL); - item->card[j] = atoi(data); - } - } - - md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX ); - - md->amount = i; - Sql_FreeResult(sql_handle); - - md->unchecked = 0; - md->unread = 0; - for (i = 0; i < md->amount; i++) - { - msg = &md->msg[i]; - if( msg->status == MAIL_NEW ) - { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) - Sql_ShowDebug(sql_handle); - - msg->status = MAIL_UNREAD; - md->unchecked++; - } - else if ( msg->status == MAIL_UNREAD ) - md->unread++; - } - - ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); - return 1; + int i, j; + struct mail_message *msg; + struct item *item; + char *data; + StringBuf buf; + + memset(md, 0, sizeof(struct mail_data)); + md->amount = 0; + md->full = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + + // I keep the `status` < 3 just in case someone forget to apply the sqlfix + StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", + mail_db, char_id, MAIL_MAX_INBOX + 1); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + msg = &md->msg[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); + msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); + msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); + safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); + msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + msg->zeny = atoi(data); + item = &msg->item; + Sql_GetData(sql_handle,10, &data, NULL); + item->amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + item->attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); + item->identify = atoi(data); + item->expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) { + Sql_GetData(sql_handle, 15 + j, &data, NULL); + item->card[j] = atoi(data); + } + } + + md->full = (Sql_NumRows(sql_handle) > MAIL_MAX_INBOX); + + md->amount = i; + Sql_FreeResult(sql_handle); + + md->unchecked = 0; + md->unread = 0; + for (i = 0; i < md->amount; i++) { + msg = &md->msg[i]; + if (msg->status == MAIL_NEW) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id)) + Sql_ShowDebug(sql_handle); + + msg->status = MAIL_UNREAD; + md->unchecked++; + } else if (msg->status == MAIL_UNREAD) + md->unread++; + } + + ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); + return 1; } /// Stores a single message in the database. /// Returns the message's ID if successful (or 0 if it fails). -int mail_savemessage(struct mail_message* msg) +int mail_savemessage(struct mail_message *msg) { - StringBuf buf; - SqlStmt* stmt; - int j; - - // build message save query - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", - msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - // prepare and execute query - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - msg->id = 0; - } else - msg->id = (int)SqlStmt_LastInsertId(stmt); - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return msg->id; + StringBuf buf; + SqlStmt *stmt; + int j; + + // build message save query + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", + msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + // prepare and execute query + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + msg->id = 0; + } else + msg->id = (int)SqlStmt_LastInsertId(stmt); + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return msg->id; } /// Retrieves a single message from the database. /// Returns true if the operation succeeds (or false if it fails). -static bool mail_loadmessage(int mail_id, struct mail_message* msg) +static bool mail_loadmessage(int mail_id, struct mail_message *msg) { - int j; - StringBuf buf; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) - || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - StringBuf_Destroy(&buf); - return false; - } - else - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); msg->item.refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); - msg->item.expire_time = 0; - - for( j = 0; j < MAX_SLOTS; j++ ) - { - Sql_GetData(sql_handle,15 + j, &data, NULL); - msg->item.card[j] = atoi(data); - } - } - - StringBuf_Destroy(&buf); - Sql_FreeResult(sql_handle); - - return true; + int j; + StringBuf buf; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) + || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + StringBuf_Destroy(&buf); + return false; + } else { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); + msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); + msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); + safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); + msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + msg->zeny = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); + msg->item.amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); + msg->item.nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); + msg->item.refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + msg->item.attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); + msg->item.identify = atoi(data); + msg->item.expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) { + Sql_GetData(sql_handle,15 + j, &data, NULL); + msg->item.card[j] = atoi(data); + } + } + + StringBuf_Destroy(&buf); + Sql_FreeResult(sql_handle); + + return true; } /*========================================== @@ -196,22 +216,22 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg) *------------------------------------------*/ static void mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag) { - struct mail_data md; - mail_fromsql(char_id, &md); - - //FIXME: dumping the whole structure like this is unsafe [ultramage] - WFIFOHEAD(fd, sizeof(md) + 9); - WFIFOW(fd,0) = 0x3848; - WFIFOW(fd,2) = sizeof(md) + 9; - WFIFOL(fd,4) = char_id; - WFIFOB(fd,8) = flag; - memcpy(WFIFOP(fd,9),&md,sizeof(md)); - WFIFOSET(fd,WFIFOW(fd,2)); + struct mail_data md; + mail_fromsql(char_id, &md); + + //FIXME: dumping the whole structure like this is unsafe [ultramage] + WFIFOHEAD(fd, sizeof(md) + 9); + WFIFOW(fd,0) = 0x3848; + WFIFOW(fd,2) = sizeof(md) + 9; + WFIFOL(fd,4) = char_id; + WFIFOB(fd,8) = flag; + memcpy(WFIFOP(fd,9),&md,sizeof(md)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_requestinbox(int fd) { - mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); + mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); } /*========================================== @@ -219,9 +239,9 @@ static void mapif_parse_Mail_requestinbox(int fd) *------------------------------------------*/ static void mapif_parse_Mail_read(int fd) { - int mail_id = RFIFOL(fd,2); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) - Sql_ShowDebug(sql_handle); + int mail_id = RFIFOL(fd,2); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id)) + Sql_ShowDebug(sql_handle); } /*========================================== @@ -229,58 +249,57 @@ static void mapif_parse_Mail_read(int fd) *------------------------------------------*/ static bool mail_DeleteAttach(int mail_id) { - StringBuf buf; - int i; + StringBuf buf; + int i; - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ", `card%d` = '0'", i); - StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ", `card%d` = '0'", i); + StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); - return false; - } + return false; + } - StringBuf_Destroy(&buf); - return true; + StringBuf_Destroy(&buf); + return true; } static void mapif_Mail_getattach(int fd, int char_id, int mail_id) { - struct mail_message msg; + struct mail_message msg; - if( !mail_loadmessage(mail_id, &msg) ) - return; + if (!mail_loadmessage(mail_id, &msg)) + return; - if( msg.dest_id != char_id ) - return; + if (msg.dest_id != char_id) + return; - if( msg.status != MAIL_READ ) - return; + if (msg.status != MAIL_READ) + return; - if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 ) - return; // No Attachment + if ((msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1) + return; // No Attachment - if( !mail_DeleteAttach(mail_id) ) - return; + if (!mail_DeleteAttach(mail_id)) + return; - WFIFOHEAD(fd, sizeof(struct item) + 12); - WFIFOW(fd,0) = 0x384a; - WFIFOW(fd,2) = sizeof(struct item) + 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; - memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct item) + 12); + WFIFOW(fd,0) = 0x384a; + WFIFOW(fd,2) = sizeof(struct item) + 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; + memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_getattach(int fd) { - mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -288,24 +307,23 @@ static void mapif_parse_Mail_getattach(int fd) *------------------------------------------*/ static void mapif_Mail_delete(int fd, int char_id, int mail_id) { - bool failed = false; - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - { - Sql_ShowDebug(sql_handle); - failed = true; - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384b; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = failed; - WFIFOSET(fd,11); + bool failed = false; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) { + Sql_ShowDebug(sql_handle); + failed = true; + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384b; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = failed; + WFIFOSET(fd,11); } static void mapif_parse_Mail_delete(int fd) { - mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -313,17 +331,17 @@ static void mapif_parse_Mail_delete(int fd) *------------------------------------------*/ void mapif_Mail_new(struct mail_message *msg) { - unsigned char buf[74]; - - if( !msg || !msg->id ) - return; - - WBUFW(buf,0) = 0x3849; - WBUFL(buf,2) = msg->dest_id; - WBUFL(buf,6) = msg->id; - memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); - memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); - mapif_sendall(buf, 74); + unsigned char buf[74]; + + if (!msg || !msg->id) + return; + + WBUFW(buf,0) = 0x3849; + WBUFL(buf,2) = msg->dest_id; + WBUFL(buf,6) = msg->id; + memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); + memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); + mapif_sendall(buf, 74); } /*========================================== @@ -331,120 +349,116 @@ void mapif_Mail_new(struct mail_message *msg) *------------------------------------------*/ static void mapif_Mail_return(int fd, int char_id, int mail_id) { - struct mail_message msg; - int new_mail = 0; - - if( mail_loadmessage(mail_id, &msg) ) - { - if( msg.dest_id != char_id) - return; - else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - Sql_ShowDebug(sql_handle); - else - { - char temp_[MAIL_TITLE_LENGTH]; - - // swap sender and receiver - swap(msg.send_id, msg.dest_id); - safestrncpy(temp_, msg.send_name, NAME_LENGTH); - safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); - safestrncpy(msg.dest_name, temp_, NAME_LENGTH); - - // set reply message title - snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); - safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); - - msg.status = MAIL_NEW; - msg.timestamp = time(NULL); - - new_mail = mail_savemessage(&msg); - mapif_Mail_new(&msg); - } - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = (new_mail == 0); - WFIFOSET(fd,11); + struct mail_message msg; + int new_mail = 0; + + if (mail_loadmessage(mail_id, &msg)) { + if (msg.dest_id != char_id) + return; + else if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) + Sql_ShowDebug(sql_handle); + else { + char temp_[MAIL_TITLE_LENGTH]; + + // swap sender and receiver + swap(msg.send_id, msg.dest_id); + safestrncpy(temp_, msg.send_name, NAME_LENGTH); + safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); + safestrncpy(msg.dest_name, temp_, NAME_LENGTH); + + // set reply message title + snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); + safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); + + msg.status = MAIL_NEW; + msg.timestamp = time(NULL); + + new_mail = mail_savemessage(&msg); + mapif_Mail_new(&msg); + } + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = (new_mail == 0); + WFIFOSET(fd,11); } static void mapif_parse_Mail_return(int fd) { - mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== * Send Mail *------------------------------------------*/ -static void mapif_Mail_send(int fd, struct mail_message* msg) +static void mapif_Mail_send(int fd, struct mail_message *msg) { - int len = sizeof(struct mail_message) + 4; - - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x384d; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); - WFIFOSET(fd,len); + int len = sizeof(struct mail_message) + 4; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x384d; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); + WFIFOSET(fd,len); } static void mapif_parse_Mail_send(int fd) { - struct mail_message msg; - char esc_name[NAME_LENGTH*2+1]; - int account_id = 0; - - if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) - return; - - account_id = RFIFOL(fd,4); - memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); - - // Try to find the Dest Char by Name - Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char *data; - Sql_GetData(sql_handle, 0, &data, NULL); - if (atoi(data) != account_id) - { // Cannot send mail to char in the same account - Sql_GetData(sql_handle, 1, &data, NULL); - msg.dest_id = atoi(data); - } - } - Sql_FreeResult(sql_handle); - msg.status = MAIL_NEW; - - if( msg.dest_id > 0 ) - msg.id = mail_savemessage(&msg); - - mapif_Mail_send(fd, &msg); // notify sender - mapif_Mail_new(&msg); // notify recipient + struct mail_message msg; + char esc_name[NAME_LENGTH*2+1]; + int account_id = 0; + + if (RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) + return; + + account_id = RFIFOL(fd,4); + memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); + + // Try to find the Dest Char by Name + Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + if (atoi(data) != account_id) { + // Cannot send mail to char in the same account + Sql_GetData(sql_handle, 1, &data, NULL); + msg.dest_id = atoi(data); + } + } + Sql_FreeResult(sql_handle); + msg.status = MAIL_NEW; + + if (msg.dest_id > 0) + msg.id = mail_savemessage(&msg); + + mapif_Mail_send(fd, &msg); // notify sender + mapif_Mail_new(&msg); // notify recipient } -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item) +void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item) { - struct mail_message msg; - memset(&msg, 0, sizeof(struct mail_message)); - - msg.send_id = send_id; - safestrncpy(msg.send_name, send_name, NAME_LENGTH); - msg.dest_id = dest_id; - safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); - safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); - safestrncpy(msg.body, body, MAIL_BODY_LENGTH); - msg.zeny = zeny; - if( item != NULL ) - memcpy(&msg.item, item, sizeof(struct item)); - - msg.timestamp = time(NULL); - - mail_savemessage(&msg); - mapif_Mail_new(&msg); + struct mail_message msg; + memset(&msg, 0, sizeof(struct mail_message)); + + msg.send_id = send_id; + safestrncpy(msg.send_name, send_name, NAME_LENGTH); + msg.dest_id = dest_id; + safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); + safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); + safestrncpy(msg.body, body, MAIL_BODY_LENGTH); + msg.zeny = zeny; + if (item != NULL) + memcpy(&msg.item, item, sizeof(struct item)); + + msg.timestamp = time(NULL); + + mail_savemessage(&msg); + mapif_Mail_new(&msg); } /*========================================== @@ -452,26 +466,37 @@ void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* *------------------------------------------*/ int inter_mail_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3048: mapif_parse_Mail_requestinbox(fd); break; - case 0x3049: mapif_parse_Mail_read(fd); break; - case 0x304a: mapif_parse_Mail_getattach(fd); break; - case 0x304b: mapif_parse_Mail_delete(fd); break; - case 0x304c: mapif_parse_Mail_return(fd); break; - case 0x304d: mapif_parse_Mail_send(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3048: + mapif_parse_Mail_requestinbox(fd); + break; + case 0x3049: + mapif_parse_Mail_read(fd); + break; + case 0x304a: + mapif_parse_Mail_getattach(fd); + break; + case 0x304b: + mapif_parse_Mail_delete(fd); + break; + case 0x304c: + mapif_parse_Mail_return(fd); + break; + case 0x304d: + mapif_parse_Mail_send(fd); + break; + default: + return 0; + } + return 1; } int inter_mail_sql_init(void) { - return 1; + return 1; } void inter_mail_sql_final(void) { - return; + return; } diff --git a/src/char/int_mail.h b/src/char/int_mail.h index 77db51e5b..0fef3d4ab 100644 --- a/src/char/int_mail.h +++ b/src/char/int_mail.h @@ -5,12 +5,12 @@ #define _INT_MAIL_SQL_H_ int inter_mail_parse_frommap(int fd); -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item); +void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item); int inter_mail_sql_init(void); void inter_mail_sql_final(void); -int mail_savemessage(struct mail_message* msg); +int mail_savemessage(struct mail_message *msg); void mapif_Mail_new(struct mail_message *msg); #endif /* _INT_MAIL_SQL_H_ */ diff --git a/src/char/int_mercenary.c b/src/char/int_mercenary.c index 3b3714416..528f05524 100644 --- a/src/char/int_mercenary.c +++ b/src/char/int_mercenary.c @@ -17,185 +17,188 @@ bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status) { - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); status->mer_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); status->arch_calls = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); status->arch_faith = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); status->spear_calls = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); status->spear_faith = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); status->sword_calls = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); status->sword_faith = atoi(data); - Sql_FreeResult(sql_handle); - - return true; + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + status->mer_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + status->arch_calls = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + status->arch_faith = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + status->spear_calls = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + status->spear_faith = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + status->sword_calls = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + status->sword_faith = atoi(data); + Sql_FreeResult(sql_handle); + + return true; } bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) { - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } bool mercenary_owner_delete(int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id)) + Sql_ShowDebug(sql_handle); - return true; + return true; } -bool mapif_mercenary_save(struct s_mercenary* merc) +bool mapif_mercenary_save(struct s_mercenary *merc) { - bool flag = true; + bool flag = true; - if( merc->mercenary_id == 0 ) - { // Create new DB entry - if( SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); - } - else if( SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) - { // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } + if (merc->mercenary_id == 0) { + // Create new DB entry + if (SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else + merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); + } else if (SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id)) { + // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } - return flag; + return flag; } bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc) { - char* data; + char *data; + + memset(merc, 0, sizeof(struct s_mercenary)); + merc->mercenary_id = merc_id; + merc->char_id = char_id; - memset(merc, 0, sizeof(struct s_mercenary)); - merc->mercenary_id = merc_id; - merc->char_id = char_id; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } + Sql_GetData(sql_handle, 0, &data, NULL); + merc->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + merc->hp = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + merc->sp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + merc->kill_count = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + merc->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if (save_log) + ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if( save_log ) - ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - - return true; + return true; } bool mapif_mercenary_delete(int merc_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } static void mapif_mercenary_send(int fd, struct s_mercenary *merc, unsigned char flag) { - int size = sizeof(struct s_mercenary) + 5; + int size = sizeof(struct s_mercenary) + 5; - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x3870; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); - WFIFOSET(fd,size); + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x3870; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); + WFIFOSET(fd,size); } -static void mapif_parse_mercenary_create(int fd, struct s_mercenary* merc) +static void mapif_parse_mercenary_create(int fd, struct s_mercenary *merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_send(fd, merc, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_send(fd, merc, result); } static void mapif_parse_mercenary_load(int fd, int merc_id, int char_id) { - struct s_mercenary merc; - bool result = mapif_mercenary_load(merc_id, char_id, &merc); - mapif_mercenary_send(fd, &merc, result); + struct s_mercenary merc; + bool result = mapif_mercenary_load(merc_id, char_id, &merc); + mapif_mercenary_send(fd, &merc, result); } static void mapif_mercenary_deleted(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3871; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3871; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } static void mapif_parse_mercenary_delete(int fd, int merc_id) { - bool result = mapif_mercenary_delete(merc_id); - mapif_mercenary_deleted(fd, result); + bool result = mapif_mercenary_delete(merc_id); + mapif_mercenary_deleted(fd, result); } static void mapif_mercenary_saved(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3872; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3872; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_mercenary_save(int fd, struct s_mercenary* merc) +static void mapif_parse_mercenary_save(int fd, struct s_mercenary *merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_saved(fd, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_saved(fd, result); } int inter_mercenary_sql_init(void) { - return 0; + return 0; } void inter_mercenary_sql_final(void) { - return; + return; } /*========================================== @@ -203,16 +206,23 @@ void inter_mercenary_sql_final(void) *------------------------------------------*/ int inter_mercenary_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3070: mapif_parse_mercenary_create(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - case 0x3071: mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3072: mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3073: mapif_parse_mercenary_save(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x3070: + mapif_parse_mercenary_create(fd, (struct s_mercenary *)RFIFOP(fd,4)); + break; + case 0x3071: + mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x3072: + mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x3073: + mapif_parse_mercenary_save(fd, (struct s_mercenary *)RFIFOP(fd,4)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_party.c b/src/char/int_party.c index a88e5c586..862a943f1 100644 --- a/src/char/int_party.c +++ b/src/char/int_party.c @@ -19,14 +19,14 @@ #include struct party_data { - struct party party; - unsigned int min_lv, max_lv; - int family; //Is this party a family? if so, this holds the child id. - unsigned char size; //Total size of party. + struct party party; + unsigned int min_lv, max_lv; + int family; //Is this party a family? if so, this holds the child id. + unsigned char size; //Total size of party. }; static struct party_data *party_pt; -static DBMap* party_db_; // int party_id -> struct party_data* +static DBMap *party_db_; // int party_id -> struct party_data* int mapif_party_broken(int party_id,int flag); int party_check_empty(struct party_data *p); @@ -35,292 +35,297 @@ int party_check_exp_share(struct party_data *p); int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); //Updates party's level range and unsets even share if broken. -static int int_party_check_lv(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - for(i=0;iparty.member[i].online || p->party.member[i].char_id == p->family ) - continue; - - lv=p->party.member[i].lv; - if (lv < p->min_lv) p->min_lv = lv; - if (lv > p->max_lv) p->max_lv = lv; - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; - mapif_party_optionchanged(0, &p->party, 0, 0); - return 0; - } - return 1; +static int int_party_check_lv(struct party_data *p) +{ + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + for (i=0; iparty.member[i].online || p->party.member[i].char_id == p->family) + continue; + + lv=p->party.member[i].lv; + if (lv < p->min_lv) p->min_lv = lv; + if (lv > p->max_lv) p->max_lv = lv; + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; + mapif_party_optionchanged(0, &p->party, 0, 0); + return 0; + } + return 1; } //Calculates the state of a party. static void int_party_calc_state(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - p->party.count = - p->size = - p->family = 0; - - //Check party size - for(i=0;iparty.member[i].lv) continue; - p->size++; - if(p->party.member[i].online) - p->party.count++; - } - if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id) ) ) { - //Child should be able to share with either of their parents [RoM] - if(p->party.member[0].class_&0x2000) //first slot is the child? - p->family = p->party.member[0].char_id; - else - p->family = p->party.member[1].char_id; - } else if( p->size == 3 ) { - //Check Family State. - p->family = char_family( - p->party.member[0].char_id, - p->party.member[1].char_id, - p->party.member[2].char_id - ); - } - //max/min levels. - for(i=0;iparty.member[i].lv; - if (!lv) continue; - if(p->party.member[i].online && - //On families, the kid is not counted towards exp share rules. - p->party.member[i].char_id != p->family) - { - if( lv < p->min_lv ) p->min_lv=lv; - if( p->max_lv < lv ) p->max_lv=lv; - } - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; //Set off even share. - mapif_party_optionchanged(0, &p->party, 0, 0); - } - return; + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + p->party.count = + p->size = + p->family = 0; + + //Check party size + for (i=0; iparty.member[i].lv) continue; + p->size++; + if (p->party.member[i].online) + p->party.count++; + } + if (p->size == 2 && (char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id))) { + //Child should be able to share with either of their parents [RoM] + if (p->party.member[0].class_&0x2000) //first slot is the child? + p->family = p->party.member[0].char_id; + else + p->family = p->party.member[1].char_id; + } else if (p->size == 3) { + //Check Family State. + p->family = char_family( + p->party.member[0].char_id, + p->party.member[1].char_id, + p->party.member[2].char_id + ); + } + //max/min levels. + for (i=0; iparty.member[i].lv; + if (!lv) continue; + if (p->party.member[i].online && + //On families, the kid is not counted towards exp share rules. + p->party.member[i].char_id != p->family) { + if (lv < p->min_lv) p->min_lv=lv; + if (p->max_lv < lv) p->max_lv=lv; + } + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; //Set off even share. + mapif_party_optionchanged(0, &p->party, 0, 0); + } + return; } // Save party to mysql int inter_party_tosql(struct party *p, int flag, int index) { - // 'party' ('party_id','name','exp','item','leader_id','leader_char') - char esc_name[NAME_LENGTH*2+1];// escaped party name - int party_id; + // 'party' ('party_id','name','exp','item','leader_id','leader_char') + char esc_name[NAME_LENGTH*2+1];// escaped party name + int party_id; - if( p == NULL || p->party_id == 0 ) - return 0; - party_id = p->party_id; + if (p == NULL || p->party_id == 0) + return 0; + party_id = p->party_id; #ifdef NOISY - ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); + ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); #endif - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - - if( flag & PS_BREAK ) - {// Break the party - // we'll skip name-checking and just reset everyone with the same party id [celest] - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - Sql_ShowDebug(sql_handle); - //Remove from memory - idb_remove(party_db_, party_id); - return 1; - } - - if( flag & PS_CREATE ) - {// Create party - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " - "VALUES ('%s', '%d', '%d', '%d', '%d')", - party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); - } - - if( flag & PS_BASIC ) - {// Update party info. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", - party_db, esc_name, p->exp, p->item, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_LEADER ) - {// Update leader - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", - party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_ADDMEMBER ) - {// Add one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_DELMEMBER ) - {// Remove one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } - - if( save_log ) - ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + + if (flag & PS_BREAK) { + // Break the party + // we'll skip name-checking and just reset everyone with the same party id [celest] + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) + Sql_ShowDebug(sql_handle); + //Remove from memory + idb_remove(party_db_, party_id); + return 1; + } + + if (flag & PS_CREATE) { + // Create party + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " + "VALUES ('%s', '%d', '%d', '%d', '%d')", + party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); + } + + if (flag & PS_BASIC) { + // Update party info. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", + party_db, esc_name, p->exp, p->item, party_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_LEADER) { + // Update leader + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", + party_db, p->member[index].account_id, p->member[index].char_id, party_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_ADDMEMBER) { + // Add one party member. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_DELMEMBER) { + // Remove one party member. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id)) + Sql_ShowDebug(sql_handle); + } + + if (save_log) + ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); + return 1; } // Read party from mysql -struct party_data *inter_party_fromsql(int party_id) -{ - int leader_id = 0; - int leader_char = 0; - struct party_data* p; - struct party_member* m; - char* data; - size_t len; - int i; +struct party_data *inter_party_fromsql(int party_id) { + int leader_id = 0; + int leader_char = 0; + struct party_data *p; + struct party_member *m; + char *data; + size_t len; + int i; #ifdef NOISY - ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); + ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); #endif - if( party_id <= 0 ) - return NULL; - - //Load from memory - p = (struct party_data*)idb_get(party_db_, party_id); - if( p != NULL ) - return p; - - p = party_pt; - memset(p, 0, sizeof(struct party_data)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL; - - p->party.party_id = party_id; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data); - Sql_FreeResult(sql_handle); - - // Load members - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - m = &p->party.member[i]; - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data); - m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); - //Add party to memory. - CREATE(p, struct party_data, 1); - memcpy(p, party_pt, sizeof(struct party_data)); - //init state - int_party_calc_state(p); - idb_put(party_db_, party_id, p); - return p; + if (party_id <= 0) + return NULL; + + //Load from memory + p = (struct party_data *)idb_get(party_db_, party_id); + if (p != NULL) + return p; + + p = party_pt; + memset(p, 0, sizeof(struct party_data)); + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return NULL; + + p->party.party_id = party_id; + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(p->party.name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + p->party.exp = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 3, &data, NULL); + p->party.item = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + leader_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + leader_char = atoi(data); + Sql_FreeResult(sql_handle); + + // Load members + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + for (i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + m = &p->party.member[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(m->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); + m->lv = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + m->map = mapindex_name2id(data); + Sql_GetData(sql_handle, 5, &data, NULL); + m->online = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 6, &data, NULL); + m->class_ = atoi(data); + m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); + } + Sql_FreeResult(sql_handle); + + if (save_log) + ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); + //Add party to memory. + CREATE(p, struct party_data, 1); + memcpy(p, party_pt, sizeof(struct party_data)); + //init state + int_party_calc_state(p); + idb_put(party_db_, party_id, p); + return p; } int inter_party_sql_init(void) { - //memory alloc - party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (!party_pt) { - ShowFatalError("inter_party_sql_init: Out of Memory!\n"); - exit(EXIT_FAILURE); - } - - /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] - ShowStatus("cleaning party table...\n"); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", - party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) - Sql_ShowDebug(sql_handle); - */ - return 0; + //memory alloc + party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + party_pt = (struct party_data *)aCalloc(sizeof(struct party_data), 1); + if (!party_pt) { + ShowFatalError("inter_party_sql_init: Out of Memory!\n"); + exit(EXIT_FAILURE); + } + + /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] + ShowStatus("cleaning party table...\n"); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", + party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) + Sql_ShowDebug(sql_handle); + */ + return 0; } void inter_party_sql_final(void) { - party_db_->destroy(party_db_, NULL); - aFree(party_pt); - return; + party_db_->destroy(party_db_, NULL); + aFree(party_pt); + return; } // Search for the party according to its name -struct party_data* search_partyname(char* str) -{ - char esc_name[NAME_LENGTH*2+1]; - char* data; - struct party_data* p = NULL; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, NULL); - p = inter_party_fromsql(atoi(data)); - } - Sql_FreeResult(sql_handle); - - return p; +struct party_data *search_partyname(char *str) { + char esc_name[NAME_LENGTH*2+1]; + char *data; + struct party_data *p = NULL; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 0, &data, NULL); + p = inter_party_fromsql(atoi(data)); + } + Sql_FreeResult(sql_handle); + + return p; } // Returns whether this party can keep having exp share or not. int party_check_exp_share(struct party_data *p) { - return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); + return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); } // Is there any member in the party? int party_check_empty(struct party_data *p) { - int i; - if (p==NULL||p->party.party_id==0) return 1; - for(i=0;iparty.member[i].account_id;i++); - if (i < MAX_PARTY) return 0; - // If there is no member, then break the party - mapif_party_broken(p->party.party_id,0); - inter_party_tosql(&p->party, PS_BREAK, 0); - return 1; + int i; + if (p==NULL||p->party.party_id==0) return 1; + for (i=0; iparty.member[i].account_id; i++); + if (i < MAX_PARTY) return 0; + // If there is no member, then break the party + mapif_party_broken(p->party.party_id,0); + inter_party_tosql(&p->party, PS_BREAK, 0); + return 1; } //------------------------------------------------------------------- @@ -330,133 +335,135 @@ int party_check_empty(struct party_data *p) // Create a party whether or not int mapif_party_created(int fd,int account_id,int char_id,struct party *p) { - WFIFOHEAD(fd, 39); - WFIFOW(fd,0)=0x3820; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=char_id; - if(p!=NULL){ - WFIFOB(fd,10)=0; - WFIFOL(fd,11)=p->party_id; - memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); - ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); - }else{ - WFIFOB(fd,10)=1; - WFIFOL(fd,11)=0; - memset(WFIFOP(fd,15),0,NAME_LENGTH); - } - WFIFOSET(fd,39); - - return 0; + WFIFOHEAD(fd, 39); + WFIFOW(fd,0)=0x3820; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=char_id; + if (p!=NULL) { + WFIFOB(fd,10)=0; + WFIFOL(fd,11)=p->party_id; + memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); + ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); + } else { + WFIFOB(fd,10)=1; + WFIFOL(fd,11)=0; + memset(WFIFOP(fd,15),0,NAME_LENGTH); + } + WFIFOSET(fd,39); + + return 0; } //Party information not found static void mapif_party_noinfo(int fd, int party_id, int char_id) { - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = party_id; - WFIFOSET(fd,12); - ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3821; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = party_id; + WFIFOSET(fd,12); + ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); } //Digest party information -static void mapif_party_info(int fd, struct party* p, int char_id) +static void mapif_party_info(int fd, struct party *p, int char_id) { - unsigned char buf[8 + sizeof(struct party)]; - WBUFW(buf,0) = 0x3821; - WBUFW(buf,2) = 8 + sizeof(struct party); - WBUFL(buf,4) = char_id; - memcpy(WBUFP(buf,8), p, sizeof(struct party)); - - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); + unsigned char buf[8 + sizeof(struct party)]; + WBUFW(buf,0) = 0x3821; + WBUFW(buf,2) = 8 + sizeof(struct party); + WBUFL(buf,4) = char_id; + memcpy(WBUFP(buf,8), p, sizeof(struct party)); + + if (fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); } //Whether or not additional party members -int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3822; - WFIFOL(fd,2) = party_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd,15); - - return 0; +int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) +{ + WFIFOHEAD(fd, 15); + WFIFOW(fd,0) = 0x3822; + WFIFOL(fd,2) = party_id; + WFIFOL(fd,6) = account_id; + WFIFOL(fd,10) = char_id; + WFIFOB(fd,14) = flag; + WFIFOSET(fd,15); + + return 0; } // Party setting change notification int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3823; - WBUFL(buf,2)=p->party_id; - WBUFL(buf,6)=account_id; - WBUFW(buf,10)=p->exp; - WBUFW(buf,12)=p->item; - WBUFB(buf,14)=flag; - if(flag==0) - mapif_sendall(buf,15); - else - mapif_send(fd,buf,15); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3823; + WBUFL(buf,2)=p->party_id; + WBUFL(buf,6)=account_id; + WBUFW(buf,10)=p->exp; + WBUFW(buf,12)=p->item; + WBUFB(buf,14)=flag; + if (flag==0) + mapif_sendall(buf,15); + else + mapif_send(fd,buf,15); + return 0; } //Withdrawal notification party -int mapif_party_withdraw(int party_id,int account_id, int char_id) { - unsigned char buf[16]; - - WBUFW(buf,0) = 0x3824; - WBUFL(buf,2) = party_id; - WBUFL(buf,6) = account_id; - WBUFL(buf,10) = char_id; - mapif_sendall(buf, 14); - return 0; +int mapif_party_withdraw(int party_id,int account_id, int char_id) +{ + unsigned char buf[16]; + + WBUFW(buf,0) = 0x3824; + WBUFL(buf,2) = party_id; + WBUFL(buf,6) = account_id; + WBUFL(buf,10) = char_id; + mapif_sendall(buf, 14); + return 0; } //Party map update notification int mapif_party_membermoved(struct party *p,int idx) { - unsigned char buf[20]; - - WBUFW(buf,0) = 0x3825; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = p->member[idx].account_id; - WBUFL(buf,10) = p->member[idx].char_id; - WBUFW(buf,14) = p->member[idx].map; - WBUFB(buf,16) = p->member[idx].online; - WBUFW(buf,17) = p->member[idx].lv; - mapif_sendall(buf, 19); - return 0; + unsigned char buf[20]; + + WBUFW(buf,0) = 0x3825; + WBUFL(buf,2) = p->party_id; + WBUFL(buf,6) = p->member[idx].account_id; + WBUFL(buf,10) = p->member[idx].char_id; + WBUFW(buf,14) = p->member[idx].map; + WBUFB(buf,16) = p->member[idx].online; + WBUFW(buf,17) = p->member[idx].lv; + mapif_sendall(buf, 19); + return 0; } //Dissolution party notification int mapif_party_broken(int party_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3826; - WBUFL(buf,2)=party_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - //printf("int_party: broken %d\n",party_id); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3826; + WBUFL(buf,2)=party_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + //printf("int_party: broken %d\n",party_id); + return 0; } //Remarks in the party int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - WBUFW(buf,0)=0x3827; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=party_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + WBUFW(buf,0)=0x3827; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=party_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } //------------------------------------------------------------------- @@ -466,273 +473,267 @@ int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) // Create Party int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { - struct party_data *p; - int i; - if( (p=search_partyname(name))!=NULL){ - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } - - p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); - - memcpy(p->party.name,name,NAME_LENGTH); - p->party.exp=0; - p->party.item=(item?1:0)|(item2?2:0); - - memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader=1; - p->party.member[0].online=1; - - p->party.party_id=-1;//New party. - if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { - //Add party to db - int_party_calc_state(p); - idb_put(party_db_, p->party.party_id, p); - mapif_party_info(fd, &p->party, 0); - mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); - } else { //Failed to create party. - aFree(p); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - } - - return 0; + struct party_data *p; + int i; + if ((p=search_partyname(name))!=NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } + + p = (struct party_data *)aCalloc(1, sizeof(struct party_data)); + + memcpy(p->party.name,name,NAME_LENGTH); + p->party.exp=0; + p->party.item=(item?1:0)|(item2?2:0); + + memcpy(&p->party.member[0], leader, sizeof(struct party_member)); + p->party.member[0].leader=1; + p->party.member[0].online=1; + + p->party.party_id=-1;//New party. + if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { + //Add party to db + int_party_calc_state(p); + idb_put(party_db_, p->party.party_id, p); + mapif_party_info(fd, &p->party, 0); + mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); + } else { //Failed to create party. + aFree(p); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + } + + return 0; } // Party information request static void mapif_parse_PartyInfo(int fd, int party_id, int char_id) { - struct party_data *p; - p = inter_party_fromsql(party_id); + struct party_data *p; + p = inter_party_fromsql(party_id); - if (p) - mapif_party_info(fd, &p->party, char_id); - else - mapif_party_noinfo(fd, party_id, char_id); + if (p) + mapif_party_info(fd, &p->party, char_id); + else + mapif_party_noinfo(fd, party_id, char_id); } // Add a player to party request int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if( p == NULL || p->size == MAX_PARTY ) { - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); - if( i == MAX_PARTY ) - {// Party full - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - memcpy(&p->party.member[i], member, sizeof(struct party_member)); - p->party.member[i].leader = 0; - if (p->party.member[i].online) p->party.count++; - p->size++; - if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] - int_party_calc_state(p); - else //Check even share range. - if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - - mapif_party_info(-1, &p->party, 0); - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); - inter_party_tosql(&p->party, PS_ADDMEMBER, i); - - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if (p == NULL || p->size == MAX_PARTY) { + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == 0); + if (i == MAX_PARTY) { + // Party full + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + memcpy(&p->party.member[i], member, sizeof(struct party_member)); + p->party.member[i].leader = 0; + if (p->party.member[i].online) p->party.count++; + p->size++; + if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] + int_party_calc_state(p); + else //Check even share range. + if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + + mapif_party_info(-1, &p->party, 0); + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); + inter_party_tosql(&p->party, PS_ADDMEMBER, i); + + return 0; } //Party setting change request int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item) { - struct party_data *p; - int flag = 0; - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - p->party.exp=exp; - if( exp && !party_check_exp_share(p) ){ - flag|=0x01; - p->party.exp=0; - } - p->party.item = item&0x3; //Filter out invalid values. - mapif_party_optionchanged(fd,&p->party,account_id,flag); - inter_party_tosql(&p->party, PS_BASIC, 0); - return 0; + struct party_data *p; + int flag = 0; + p = inter_party_fromsql(party_id); + + if (!p) + return 0; + + p->party.exp=exp; + if (exp && !party_check_exp_share(p)) { + flag|=0x01; + p->party.exp=0; + } + p->party.item = item&0x3; //Filter out invalid values. + mapif_party_optionchanged(fd,&p->party,account_id,flag); + inter_party_tosql(&p->party, PS_BASIC, 0); + return 0; } //Request leave party int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) { - struct party_data *p; - int i,j=-1; - - p = inter_party_fromsql(party_id); - if( p == NULL ) - {// Party does not exists? - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - return 0; - } - - for (i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) { - break; - } - } - if (i >= MAX_PARTY) - return 0; //Member not found? - - mapif_party_withdraw(party_id, account_id, char_id); - - if (p->party.member[i].leader){ - p->party.member[i].account_id = 0; - for (j = 0; j < MAX_PARTY; j++) { - if (!p->party.member[j].account_id) - continue; - mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); - p->party.member[j].account_id = 0; - } - //Party gets deleted on the check_empty call below. - } else { - inter_party_tosql(&p->party,PS_DELMEMBER,i); - j = p->party.member[i].lv; - if(p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (j == p->min_lv || j == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - } - - if (party_check_empty(p) == 0) - mapif_party_info(-1, &p->party, 0); - return 0; + struct party_data *p; + int i,j=-1; + + p = inter_party_fromsql(party_id); + if (p == NULL) { + // Party does not exists? + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) + Sql_ShowDebug(sql_handle); + return 0; + } + + for (i = 0; i < MAX_PARTY; i++) { + if (p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) { + break; + } + } + if (i >= MAX_PARTY) + return 0; //Member not found? + + mapif_party_withdraw(party_id, account_id, char_id); + + if (p->party.member[i].leader) { + p->party.member[i].account_id = 0; + for (j = 0; j < MAX_PARTY; j++) { + if (!p->party.member[j].account_id) + continue; + mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); + p->party.member[j].account_id = 0; + } + //Party gets deleted on the check_empty call below. + } else { + inter_party_tosql(&p->party,PS_DELMEMBER,i); + j = p->party.member[i].lv; + if (p->party.member[i].online) p->party.count--; + memset(&p->party.member[i], 0, sizeof(struct party_member)); + p->size--; + if (j == p->min_lv || j == p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + } + + if (party_check_empty(p) == 0) + mapif_party_info(-1, &p->party, 0); + return 0; } // When member goes to other map or levels up. int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if (p == NULL) - return 0; - - for(i = 0; i < MAX_PARTY && - (p->party.member[i].account_id != account_id || - p->party.member[i].char_id != char_id); i++); - - if (i == MAX_PARTY) return 0; - - if (p->party.member[i].online != online) - { - p->party.member[i].online = online; - if (online) - p->party.count++; - else - p->party.count--; - // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) - // or character logging on/off has a different level (update level range using new level) - if (p->family || - (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || - (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) - ) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } - //Send online/offline update. - mapif_party_membermoved(&p->party, i); - } - - if (p->party.member[i].lv != lv) { - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } else - p->party.member[i].lv = lv; - //There is no need to send level update to map servers - //since they do nothing with it. - } - - if (p->party.member[i].map != map) { - p->party.member[i].map = map; - mapif_party_membermoved(&p->party, i); - } - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if (p == NULL) + return 0; + + for (i = 0; i < MAX_PARTY && + (p->party.member[i].account_id != account_id || + p->party.member[i].char_id != char_id); i++); + + if (i == MAX_PARTY) return 0; + + if (p->party.member[i].online != online) { + p->party.member[i].online = online; + if (online) + p->party.count++; + else + p->party.count--; + // Even share check situations: Family state (always breaks) + // character logging on/off is max/min level (update level range) + // or character logging on/off has a different level (update level range using new level) + if (p->family || + (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || + (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) + ) { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } + //Send online/offline update. + mapif_party_membermoved(&p->party, i); + } + + if (p->party.member[i].lv != lv) { + if (p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } else + p->party.member[i].lv = lv; + //There is no need to send level update to map servers + //since they do nothing with it. + } + + if (p->party.member[i].map != map) { + p->party.member[i].map = map; + mapif_party_membermoved(&p->party, i); + } + return 0; } //Request party dissolution int mapif_parse_BreakParty(int fd,int party_id) { - struct party_data *p; + struct party_data *p; - p = inter_party_fromsql(party_id); + p = inter_party_fromsql(party_id); - if(!p) - return 0; - inter_party_tosql(&p->party,PS_BREAK,0); - mapif_party_broken(fd,party_id); - return 0; + if (!p) + return 0; + inter_party_tosql(&p->party,PS_BREAK,0); + mapif_party_broken(fd,party_id); + return 0; } //Party sending the message int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len) { - return mapif_party_message(party_id,account_id,mes,len, fd); + return mapif_party_message(party_id,account_id,mes,len, fd); } int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - for (i = 0; i < MAX_PARTY; i++) - { - if(p->party.member[i].leader) - p->party.member[i].leader = 0; - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - { - p->party.member[i].leader = 1; - inter_party_tosql(&p->party,PS_LEADER, i); - } - } - return 1; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + + if (!p) + return 0; + + for (i = 0; i < MAX_PARTY; i++) { + if (p->party.member[i].leader) + p->party.member[i].leader = 0; + if (p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) { + p->party.member[i].leader = 1; + inter_party_tosql(&p->party,PS_LEADER, i); + } + } + return 1; } @@ -741,123 +742,139 @@ int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id // Data packet length is set to inter.c that you // Do NOT go and check the packet length, RFIFOSKIP is done by the caller // Return : -// 0 : error -// 1 : ok +// 0 : error +// 1 : ok int inter_party_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; - case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break; - case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; - case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; - case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; - case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; - case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3020: + mapif_parse_CreateParty(fd, (char *)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member *)RFIFOP(fd,30)); + break; + case 0x3021: + mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + break; + case 0x3022: + mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member *)RFIFOP(fd,8)); + break; + case 0x3023: + mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); + break; + case 0x3024: + mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + break; + case 0x3025: + mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); + break; + case 0x3026: + mapif_parse_BreakParty(fd, RFIFOL(fd,2)); + break; + case 0x3027: + mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char *)RFIFOP(fd,12), RFIFOW(fd,2)-12); + break; + case 0x3029: + mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + break; + default: + return 0; + } + return 1; } //Leave request from the server (for delete character) int inter_party_leave(int party_id,int account_id, int char_id) { - return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); + return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); } int inter_party_CharOnline(int char_id, int party_id) { - struct party_data* p; - int i; - - if( party_id == -1 ) - {// Get party_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - p = inter_party_fromsql(party_id); - if(!p) { - ShowError("Character %d's party %d not found!\n", char_id, party_id); - return 0; - } - - //Set member online - for(i=0; iparty.member[i].char_id == char_id) { - if (!p->party.member[i].online) { - p->party.member[i].online = 1; - p->party.count++; - if (p->party.member[i].lv < p->min_lv || - p->party.member[i].lv > p->max_lv) - int_party_check_lv(p); - } - break; - } - } - return 1; + struct party_data *p; + int i; + + if (party_id == -1) { + // Get party_id from the database + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + p = inter_party_fromsql(party_id); + if (!p) { + ShowError("Character %d's party %d not found!\n", char_id, party_id); + return 0; + } + + //Set member online + for (i=0; iparty.member[i].char_id == char_id) { + if (!p->party.member[i].online) { + p->party.member[i].online = 1; + p->party.count++; + if (p->party.member[i].lv < p->min_lv || + p->party.member[i].lv > p->max_lv) + int_party_check_lv(p); + } + break; + } + } + return 1; } -int inter_party_CharOffline(int char_id, int party_id) { - struct party_data *p=NULL; - int i; - - if( party_id == -1 ) - {// Get guild_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - //Character has a party, set character offline and check if they were the only member online - if ((p = inter_party_fromsql(party_id)) == NULL) - return 0; - - //Set member offline - for(i=0; i< MAX_PARTY; i++) { - if(p->party.member[i].char_id == char_id) - { - p->party.member[i].online = 0; - p->party.count--; - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - int_party_check_lv(p); - break; - } - } - - if(!p->party.count) - //Parties don't have any data that needs be saved at this point... so just remove it from memory. - idb_remove(party_db_, party_id); - return 1; +int inter_party_CharOffline(int char_id, int party_id) +{ + struct party_data *p=NULL; + int i; + + if (party_id == -1) { + // Get guild_id from the database + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + //Character has a party, set character offline and check if they were the only member online + if ((p = inter_party_fromsql(party_id)) == NULL) + return 0; + + //Set member offline + for (i=0; i< MAX_PARTY; i++) { + if (p->party.member[i].char_id == char_id) { + p->party.member[i].online = 0; + p->party.count--; + if (p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + int_party_check_lv(p); + break; + } + } + + if (!p->party.count) + //Parties don't have any data that needs be saved at this point... so just remove it from memory. + idb_remove(party_db_, party_id); + return 1; } diff --git a/src/char/int_party.h b/src/char/int_party.h index d8cdcdc6a..27df25f15 100644 --- a/src/char/int_party.h +++ b/src/char/int_party.h @@ -6,12 +6,12 @@ //Party Flags on what to save/delete. enum { - PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) - PS_BASIC = 0x02, //Update basic party info. - PS_LEADER = 0x04, //Update party's leader - PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) - PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) - PS_BREAK = 0x20, //Specify that this party must be deleted. + PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) + PS_BASIC = 0x02, //Update basic party info. + PS_LEADER = 0x04, //Update party's leader + PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) + PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) + PS_BREAK = 0x20, //Specify that this party must be deleted. }; struct party; diff --git a/src/char/int_pet.c b/src/char/int_pet.c index 114398290..e04138c0a 100644 --- a/src/char/int_pet.c +++ b/src/char/int_pet.c @@ -18,292 +18,319 @@ struct s_pet *pet_pt; //--------------------------------------------------------- -int inter_pet_tosql(int pet_id, struct s_pet* p) +int inter_pet_tosql(int pet_id, struct s_pet *p) { - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - char esc_name[NAME_LENGTH*2+1];// escaped pet name - - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( pet_id == -1 ) - {// New pet. - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - p->pet_id = (int)Sql_LastInsertId(sql_handle); - } - else - {// Update pet. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - } - - if (save_log) - ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); - return 1; + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + char esc_name[NAME_LENGTH*2+1];// escaped pet name + + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if (pet_id == -1) { + // New pet. + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " + "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate)) { + Sql_ShowDebug(sql_handle); + return 0; + } + p->pet_id = (int)Sql_LastInsertId(sql_handle); + } else { + // Update pet. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + } + + if (save_log) + ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); + return 1; } -int inter_pet_fromsql(int pet_id, struct s_pet* p) +int inter_pet_fromsql(int pet_id, struct s_pet *p) { - char* data; - size_t len; + char *data; + size_t len; #ifdef NOISY - ShowInfo("Loading pet (%d)...\n",pet_id); + ShowInfo("Loading pet (%d)...\n",pet_id); #endif - memset(p, 0, sizeof(struct s_pet)); - - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - p->pet_id = pet_id; - Sql_GetData(sql_handle, 1, &data, NULL); p->class_ = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); p->account_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); p->char_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); p->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); p->egg_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); p->equip = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); p->intimate = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); p->incuvate = atoi(data); - - Sql_FreeResult(sql_handle); - - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( save_log ) - ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); - } - return 0; + memset(p, 0, sizeof(struct s_pet)); + + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + p->pet_id = pet_id; + Sql_GetData(sql_handle, 1, &data, NULL); + p->class_ = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); + p->account_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + p->char_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + p->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + p->egg_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + p->equip = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + p->intimate = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + p->hungry = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + p->rename_flag = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + p->incuvate = atoi(data); + + Sql_FreeResult(sql_handle); + + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if (save_log) + ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); + } + return 0; } //---------------------------------------------- -int inter_pet_sql_init(void){ - //memory alloc - pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - return 0; +int inter_pet_sql_init(void) +{ + //memory alloc + pet_pt = (struct s_pet *)aCalloc(sizeof(struct s_pet), 1); + return 0; } -void inter_pet_sql_final(void){ - if (pet_pt) aFree(pet_pt); - return; +void inter_pet_sql_final(void) +{ + if (pet_pt) aFree(pet_pt); + return; } //---------------------------------- -int inter_pet_delete(int pet_id){ - ShowInfo("delete pet request: %d...\n",pet_id); +int inter_pet_delete(int pet_id) +{ + ShowInfo("delete pet request: %d...\n",pet_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) + Sql_ShowDebug(sql_handle); + return 0; } //------------------------------------------------------ int mapif_pet_created(int fd, int account_id, struct s_pet *p) { - WFIFOHEAD(fd, 11); - WFIFOW(fd, 0) =0x3880; - WFIFOL(fd, 2) =account_id; - if(p!=NULL){ - WFIFOB(fd, 6)=0; - WFIFOL(fd, 7) =p->pet_id; - ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); - }else{ - WFIFOB(fd, 6)=1; - WFIFOL(fd, 7)=0; - } - WFIFOSET(fd, 11); - - return 0; + WFIFOHEAD(fd, 11); + WFIFOW(fd, 0) =0x3880; + WFIFOL(fd, 2) =account_id; + if (p!=NULL) { + WFIFOB(fd, 6)=0; + WFIFOL(fd, 7) =p->pet_id; + ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); + } else { + WFIFOB(fd, 6)=1; + WFIFOL(fd, 7)=0; + } + WFIFOSET(fd, 11); + + return 0; } -int mapif_pet_info(int fd, int account_id, struct s_pet *p){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=0; - memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_info(int fd, int account_id, struct s_pet *p) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=0; + memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_pet_noinfo(int fd, int account_id){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=1; - memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_noinfo(int fd, int account_id) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=1; + memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_save_pet_ack(int fd, int account_id, int flag){ - WFIFOHEAD(fd, 7); - WFIFOW(fd, 0) =0x3882; - WFIFOL(fd, 2) =account_id; - WFIFOB(fd, 6) =flag; - WFIFOSET(fd, 7); +int mapif_save_pet_ack(int fd, int account_id, int flag) +{ + WFIFOHEAD(fd, 7); + WFIFOW(fd, 0) =0x3882; + WFIFOL(fd, 2) =account_id; + WFIFOB(fd, 6) =flag; + WFIFOSET(fd, 7); - return 0; + return 0; } -int mapif_delete_pet_ack(int fd, int flag){ - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) =0x3883; - WFIFOB(fd, 2) =flag; - WFIFOSET(fd, 3); +int mapif_delete_pet_ack(int fd, int flag) +{ + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) =0x3883; + WFIFOB(fd, 2) =flag; + WFIFOSET(fd, 3); - return 0; + return 0; } int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short pet_lv, short pet_egg_id, - short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) + short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) { - memset(pet_pt, 0, sizeof(struct s_pet)); - strncpy(pet_pt->name, pet_name, NAME_LENGTH); - if(incuvate == 1) - pet_pt->account_id = pet_pt->char_id = 0; - else { - pet_pt->account_id = account_id; - pet_pt->char_id = char_id; - } - pet_pt->class_ = pet_class; - pet_pt->level = pet_lv; - pet_pt->egg_id = pet_egg_id; - pet_pt->equip = pet_equip; - pet_pt->intimate = intimate; - pet_pt->hungry = hungry; - pet_pt->rename_flag = rename_flag; - pet_pt->incuvate = incuvate; - - if(pet_pt->hungry < 0) - pet_pt->hungry = 0; - else if(pet_pt->hungry > 100) - pet_pt->hungry = 100; - if(pet_pt->intimate < 0) - pet_pt->intimate = 0; - else if(pet_pt->intimate > 1000) - pet_pt->intimate = 1000; - - pet_pt->pet_id = -1; //Signal NEW pet. - if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) - mapif_pet_created(fd, account_id, pet_pt); - else //Failed... - mapif_pet_created(fd, account_id, NULL); - - return 0; + memset(pet_pt, 0, sizeof(struct s_pet)); + strncpy(pet_pt->name, pet_name, NAME_LENGTH); + if (incuvate == 1) + pet_pt->account_id = pet_pt->char_id = 0; + else { + pet_pt->account_id = account_id; + pet_pt->char_id = char_id; + } + pet_pt->class_ = pet_class; + pet_pt->level = pet_lv; + pet_pt->egg_id = pet_egg_id; + pet_pt->equip = pet_equip; + pet_pt->intimate = intimate; + pet_pt->hungry = hungry; + pet_pt->rename_flag = rename_flag; + pet_pt->incuvate = incuvate; + + if (pet_pt->hungry < 0) + pet_pt->hungry = 0; + else if (pet_pt->hungry > 100) + pet_pt->hungry = 100; + if (pet_pt->intimate < 0) + pet_pt->intimate = 0; + else if (pet_pt->intimate > 1000) + pet_pt->intimate = 1000; + + pet_pt->pet_id = -1; //Signal NEW pet. + if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) + mapif_pet_created(fd, account_id, pet_pt); + else //Failed... + mapif_pet_created(fd, account_id, NULL); + + return 0; } -int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){ - memset(pet_pt, 0, sizeof(struct s_pet)); - - inter_pet_fromsql(pet_id, pet_pt); - - if(pet_pt!=NULL) { - if(pet_pt->incuvate == 1) { - pet_pt->account_id = pet_pt->char_id = 0; - mapif_pet_info(fd, account_id, pet_pt); - } - else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id) - mapif_pet_info(fd, account_id, pet_pt); - else - mapif_pet_noinfo(fd, account_id); - } - else - mapif_pet_noinfo(fd, account_id); - - return 0; +int mapif_load_pet(int fd, int account_id, int char_id, int pet_id) +{ + memset(pet_pt, 0, sizeof(struct s_pet)); + + inter_pet_fromsql(pet_id, pet_pt); + + if (pet_pt!=NULL) { + if (pet_pt->incuvate == 1) { + pet_pt->account_id = pet_pt->char_id = 0; + mapif_pet_info(fd, account_id, pet_pt); + } else if (account_id == pet_pt->account_id && char_id == pet_pt->char_id) + mapif_pet_info(fd, account_id, pet_pt); + else + mapif_pet_noinfo(fd, account_id); + } else + mapif_pet_noinfo(fd, account_id); + + return 0; } -int mapif_save_pet(int fd, int account_id, struct s_pet *data) { - //here process pet save request. - int len; - RFIFOHEAD(fd); - len=RFIFOW(fd, 2); - if(sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); - } - - else{ - if(data->hungry < 0) - data->hungry = 0; - else if(data->hungry > 100) - data->hungry = 100; - if(data->intimate < 0) - data->intimate = 0; - else if(data->intimate > 1000) - data->intimate = 1000; - inter_pet_tosql(data->pet_id,data); - mapif_save_pet_ack(fd, account_id, 0); - } - - return 0; +int mapif_save_pet(int fd, int account_id, struct s_pet *data) +{ + //here process pet save request. + int len; + RFIFOHEAD(fd); + len=RFIFOW(fd, 2); + if (sizeof(struct s_pet)!=len-8) { + ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); + } + + else { + if (data->hungry < 0) + data->hungry = 0; + else if (data->hungry > 100) + data->hungry = 100; + if (data->intimate < 0) + data->intimate = 0; + else if (data->intimate > 1000) + data->intimate = 1000; + inter_pet_tosql(data->pet_id,data); + mapif_save_pet_ack(fd, account_id, 0); + } + + return 0; } -int mapif_delete_pet(int fd, int pet_id){ - mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); +int mapif_delete_pet(int fd, int pet_id) +{ + mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); - return 0; + return 0; } -int mapif_parse_CreatePet(int fd){ - RFIFOHEAD(fd); - mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), - RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); - return 0; +int mapif_parse_CreatePet(int fd) +{ + RFIFOHEAD(fd); + mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), + RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char *)RFIFOP(fd, 24)); + return 0; } -int mapif_parse_LoadPet(int fd){ - RFIFOHEAD(fd); - mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); - return 0; +int mapif_parse_LoadPet(int fd) +{ + RFIFOHEAD(fd); + mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); + return 0; } -int mapif_parse_SavePet(int fd){ - RFIFOHEAD(fd); - mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); - return 0; +int mapif_parse_SavePet(int fd) +{ + RFIFOHEAD(fd); + mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); + return 0; } -int mapif_parse_DeletePet(int fd){ - RFIFOHEAD(fd); - mapif_delete_pet(fd, RFIFOL(fd, 2)); - return 0; +int mapif_parse_DeletePet(int fd) +{ + RFIFOHEAD(fd); + mapif_delete_pet(fd, RFIFOL(fd, 2)); + return 0; } -int inter_pet_parse_frommap(int fd){ - RFIFOHEAD(fd); - switch(RFIFOW(fd, 0)){ - case 0x3080: mapif_parse_CreatePet(fd); break; - case 0x3081: mapif_parse_LoadPet(fd); break; - case 0x3082: mapif_parse_SavePet(fd); break; - case 0x3083: mapif_parse_DeletePet(fd); break; - default: - return 0; - } - return 1; +int inter_pet_parse_frommap(int fd) +{ + RFIFOHEAD(fd); + switch (RFIFOW(fd, 0)) { + case 0x3080: + mapif_parse_CreatePet(fd); + break; + case 0x3081: + mapif_parse_LoadPet(fd); + break; + case 0x3082: + mapif_parse_SavePet(fd); + break; + case 0x3083: + mapif_parse_DeletePet(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_quest.c b/src/char/int_quest.c index 224205412..8ba6ef95a 100644 --- a/src/char/int_quest.c +++ b/src/char/int_quest.c @@ -21,164 +21,158 @@ //Load entire questlog for a character int mapif_quests_fromsql(int char_id, struct quest questlog[]) { - int i; - struct quest tmp_quest; - SqlStmt * stmt; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - memset(&tmp_quest, 0, sizeof(struct quest)); - - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); - - SqlStmt_Free(stmt); - return i; + int i; + struct quest tmp_quest; + SqlStmt *stmt; + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + + memset(&tmp_quest, 0, sizeof(struct quest)); + + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); + + SqlStmt_Free(stmt); + return i; } //Delete a quest bool mapif_quest_delete(int char_id, int quest_id) { - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Add a quest to a questlog bool mapif_quest_add(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2])) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Update a questlog bool mapif_quest_update(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Save quests int mapif_parse_quest_save(int fd) { - int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); - int char_id = RFIFOL(fd,4); - struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; - bool success = true; - - memset(qd1, 0, sizeof(qd1)); - memset(qd2, 0, sizeof(qd2)); - if( num1 ) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); - num2 = mapif_quests_fromsql(char_id, qd2); - - for( i = 0; i < num1; i++ ) - { - ARR_FIND( 0, num2, j, qd1[i].quest_id == qd2[j].quest_id ); - if( j < num2 ) // Update existed quests - { // Only states and counts are changable. - ARR_FIND( 0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k] ); - if( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state ) - success &= mapif_quest_update(char_id, qd1[i]); - - if( j < (--num2) ) - { - memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); - memset(&qd2[num2], 0, sizeof(struct quest)); - } - - } - else // Add new quests - success &= mapif_quest_add(char_id, qd1[i]); - } - - for( i = 0; i < num2; i++ ) // Quests not in qd1 but in qd2 are to be erased. - success &= mapif_quest_delete(char_id, qd2[i].quest_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3861; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = success?1:0; - WFIFOSET(fd,7); - - return 0; + int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); + int char_id = RFIFOL(fd,4); + struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; + bool success = true; + + memset(qd1, 0, sizeof(qd1)); + memset(qd2, 0, sizeof(qd2)); + if (num1) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); + num2 = mapif_quests_fromsql(char_id, qd2); + + for (i = 0; i < num1; i++) { + ARR_FIND(0, num2, j, qd1[i].quest_id == qd2[j].quest_id); + if (j < num2) { // Update existed quests + // Only states and counts are changable. + ARR_FIND(0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k]); + if (k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state) + success &= mapif_quest_update(char_id, qd1[i]); + + if (j < (--num2)) { + memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); + memset(&qd2[num2], 0, sizeof(struct quest)); + } + + } else // Add new quests + success &= mapif_quest_add(char_id, qd1[i]); + } + + for (i = 0; i < num2; i++) // Quests not in qd1 but in qd2 are to be erased. + success &= mapif_quest_delete(char_id, qd2[i].quest_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3861; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = success?1:0; + WFIFOSET(fd,7); + + return 0; } //Send questlog to map server int mapif_parse_quest_load(int fd) { - int char_id = RFIFOL(fd,2); - struct quest tmp_questlog[MAX_QUEST_DB]; - int num_quests, i, num_complete = 0; - int complete[MAX_QUEST_DB]; - - memset(tmp_questlog, 0, sizeof(tmp_questlog)); - memset(complete, 0, sizeof(complete)); - - num_quests = mapif_quests_fromsql(char_id, tmp_questlog); - - WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); - WFIFOW(fd,0) = 0x3860; - WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; - WFIFOL(fd,4) = char_id; - - //Active and inactive quests - for( i = 0; i < num_quests; i++ ) - { - if( tmp_questlog[i].state == Q_COMPLETE ) - { - complete[num_complete++] = i; - continue; - } - memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); - } - - // Completed quests - for( i = num_quests - num_complete; i < num_quests; i++ ) - memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); - - WFIFOSET(fd,num_quests*sizeof(struct quest)+8); - - return 0; + int char_id = RFIFOL(fd,2); + struct quest tmp_questlog[MAX_QUEST_DB]; + int num_quests, i, num_complete = 0; + int complete[MAX_QUEST_DB]; + + memset(tmp_questlog, 0, sizeof(tmp_questlog)); + memset(complete, 0, sizeof(complete)); + + num_quests = mapif_quests_fromsql(char_id, tmp_questlog); + + WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); + WFIFOW(fd,0) = 0x3860; + WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; + WFIFOL(fd,4) = char_id; + + //Active and inactive quests + for (i = 0; i < num_quests; i++) { + if (tmp_questlog[i].state == Q_COMPLETE) { + complete[num_complete++] = i; + continue; + } + memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); + } + + // Completed quests + for (i = num_quests - num_complete; i < num_quests; i++) + memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); + + WFIFOSET(fd,num_quests*sizeof(struct quest)+8); + + return 0; } int inter_quest_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3060: mapif_parse_quest_load(fd); break; - case 0x3061: mapif_parse_quest_save(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3060: + mapif_parse_quest_load(fd); + break; + case 0x3061: + mapif_parse_quest_save(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 248a4521f..6f94ecc32 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -15,142 +15,155 @@ #include -#define STORAGE_MEMINC 16 +#define STORAGE_MEMINC 16 /// Save storage data to sql -int storage_tosql(int account_id, struct storage_data* p) +int storage_tosql(int account_id, struct storage_data *p) { - memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); - return 0; + memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); + return 0; } /// Load storage data to mem -int storage_fromsql(int account_id, struct storage_data* p) +int storage_fromsql(int account_id, struct storage_data *p) { - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct storage_data)); //clean up memory - p->storage_amount = 0; - - // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); - return 1; + StringBuf buf; + struct item *item; + char *data; + int i; + int j; + + memset(p, 0, sizeof(struct storage_data)); //clean up memory + p->storage_amount = 0; + + // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + item->attribute = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + item->expire_time = (unsigned int)atoi(data); + for (j = 0; j < MAX_SLOTS; ++j) { + Sql_GetData(sql_handle, 8+j, &data, NULL); + item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); + return 1; } /// Save guild_storage data to sql -int guild_storage_tosql(int guild_id, struct guild_storage* p) +int guild_storage_tosql(int guild_id, struct guild_storage *p) { - memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); - ShowInfo ("guild storage save to DB - guild: %d\n", guild_id); - return 0; + memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); + ShowInfo("guild storage save to DB - guild: %d\n", guild_id); + return 0; } /// Load guild_storage data to mem -int guild_storage_fromsql(int guild_id, struct guild_storage* p) +int guild_storage_fromsql(int guild_id, struct guild_storage *p) { - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct guild_storage)); //clean up memory - p->storage_amount = 0; - p->guild_id = guild_id; - - // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - item->expire_time = 0; - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 7+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); - return 0; + StringBuf buf; + struct item *item; + char *data; + int i; + int j; + + memset(p, 0, sizeof(struct guild_storage)); //clean up memory + p->storage_amount = 0; + p->guild_id = guild_id; + + // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + item->attribute = atoi(data); + item->expire_time = 0; + for (j = 0; j < MAX_SLOTS; ++j) { + Sql_GetData(sql_handle, 7+j, &data, NULL); + item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); + return 0; } //--------------------------------------------------------- // storage data initialize int inter_storage_sql_init(void) { - return 1; + return 1; } // storage data finalize void inter_storage_sql_final(void) { - return; + return; } // q?f[^? int inter_storage_delete(int account_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id)) + Sql_ShowDebug(sql_handle); + return 0; } int inter_guild_storage_delete(int guild_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id)) + Sql_ShowDebug(sql_handle); + return 0; } //--------------------------------------------------------- @@ -158,38 +171,38 @@ int inter_guild_storage_delete(int guild_id) int mapif_load_guild_storage(int fd,int account_id,int guild_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = sizeof(struct guild_storage)+12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = guild_id; - guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; - } - // guild does not exist - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = 0; - WFIFOSET(fd, 12); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) { + // guild exists + WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = sizeof(struct guild_storage)+12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = guild_id; + guild_storage_fromsql(guild_id, (struct guild_storage *)WFIFOP(fd,12)); + WFIFOSET(fd, WFIFOW(fd,2)); + return 0; + } + // guild does not exist + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = 0; + WFIFOSET(fd, 12); + return 0; } int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0)=0x3819; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=guild_id; - WFIFOB(fd,10)=fail; - WFIFOSET(fd,11); - return 0; + WFIFOHEAD(fd,11); + WFIFOW(fd,0)=0x3819; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=guild_id; + WFIFOB(fd,10)=fail; + WFIFOSET(fd,11); + return 0; } //--------------------------------------------------------- @@ -197,50 +210,51 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) int mapif_parse_LoadGuildStorage(int fd) { - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; + RFIFOHEAD(fd); + mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + return 0; } int mapif_parse_SaveGuildStorage(int fd) { - int guild_id; - int len; - - RFIFOHEAD(fd); - guild_id = RFIFOL(fd,8); - len = RFIFOW(fd,2); - - if( sizeof(struct guild_storage) != len - 12 ) - { - ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - Sql_FreeResult(sql_handle); - guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12)); - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); - return 0; - } - Sql_FreeResult(sql_handle); - } - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); - return 0; + int guild_id; + int len; + + RFIFOHEAD(fd); + guild_id = RFIFOL(fd,8); + len = RFIFOW(fd,2); + + if (sizeof(struct guild_storage) != len - 12) { + ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) { + // guild exists + Sql_FreeResult(sql_handle); + guild_storage_tosql(guild_id, (struct guild_storage *)RFIFOP(fd,12)); + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); + return 0; + } + Sql_FreeResult(sql_handle); + } + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); + return 0; } int inter_storage_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3018: + mapif_parse_LoadGuildStorage(fd); + break; + case 0x3019: + mapif_parse_SaveGuildStorage(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.h b/src/char/int_storage.h index 811608f82..6285a8d21 100644 --- a/src/char/int_storage.h +++ b/src/char/int_storage.h @@ -15,7 +15,7 @@ int inter_guild_storage_delete(int guild_id); int inter_storage_parse_frommap(int fd); //Exported for use in the TXT-SQL converter. -int storage_fromsql(int account_id, struct storage_data* p); +int storage_fromsql(int account_id, struct storage_data *p); int storage_tosql(int account_id,struct storage_data *p); int guild_storage_tosql(int guild_id, struct guild_storage *p); diff --git a/src/char/inter.c b/src/char/inter.c index 8863b41d8..9b33d271e 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -28,11 +28,11 @@ #include // for stat/lstat/fstat - [Dekamaster/Ultimate GM Tool] -#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) -#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis +#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) +#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis -Sql* sql_handle = NULL; +Sql *sql_handle = NULL; int char_server_port = 3306; char char_server_ip[32] = "127.0.0.1"; @@ -47,778 +47,800 @@ char main_chat_nick[16] = "Main"; // recv. packet list int inter_recv_packet_length[] = { - -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- - -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] + -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- + -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- + -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- + -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[512]; + int id, fd, count, len; + unsigned long tick; + unsigned char src[24], dst[24], msg[512]; }; -static DBMap* wis_db = NULL; // int wis_id -> struct WisData* +static DBMap *wis_db = NULL; // int wis_id -> struct WisData* static int wis_dellist[WISDELLIST_MAX], wis_delnum; #define MAX_JOB_NAMES 106 -static char* msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names +static char *msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names -const char* msg_txt(int msg_number) { - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; +const char *msg_txt(int msg_number) +{ + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "Unknown"; + return "Unknown"; } /*========================================== * Read Message Data -- at char server we only keep job names. *------------------------------------------*/ -int msg_config_read(const char* cfgName) { - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } - - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); - - while(fgets(line, sizeof(line), fp) ) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else { - msg_number = atoi(w1); - if( msg_number < 550 || msg_number > (550+MAX_JOB_NAMES) ) - continue; - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); - strcpy(msg_table[msg_number],w2); - } - } - } - - fclose(fp); - - return 0; +int msg_config_read(const char *cfgName) +{ + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } + + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else { + msg_number = atoi(w1); + if (msg_number < 550 || msg_number > (550+MAX_JOB_NAMES)) + continue; + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); + strcpy(msg_table[msg_number],w2); + } + } + } + + fclose(fp); + + return 0; } /*========================================== * Cleanup Message Data *------------------------------------------*/ -void do_final_msg(void) { - int i; - for (i = 0; i < MAX_JOB_NAMES; i++) - aFree(msg_table[i]); +void do_final_msg(void) +{ + int i; + for (i = 0; i < MAX_JOB_NAMES; i++) + aFree(msg_table[i]); } /* from pc.c due to @accinfo. any ideas to replace this crap are more than welcome. */ -const char* job_name(int class_) { - switch (class_) { - case JOB_NOVICE: - case JOB_SWORDMAN: - case JOB_MAGE: - case JOB_ARCHER: - case JOB_ACOLYTE: - case JOB_MERCHANT: - case JOB_THIEF: - return msg_txt(550 - JOB_NOVICE+class_); - - case JOB_KNIGHT: - case JOB_PRIEST: - case JOB_WIZARD: - case JOB_BLACKSMITH: - case JOB_HUNTER: - case JOB_ASSASSIN: - return msg_txt(557 - JOB_KNIGHT+class_); - - case JOB_KNIGHT2: - return msg_txt(557); - - case JOB_CRUSADER: - case JOB_MONK: - case JOB_SAGE: - case JOB_ROGUE: - case JOB_ALCHEMIST: - case JOB_BARD: - case JOB_DANCER: - return msg_txt(563 - JOB_CRUSADER+class_); - - case JOB_CRUSADER2: - return msg_txt(563); - - case JOB_WEDDING: - case JOB_SUPER_NOVICE: - case JOB_GUNSLINGER: - case JOB_NINJA: - case JOB_XMAS: - return msg_txt(570 - JOB_WEDDING+class_); - - case JOB_SUMMER: - return msg_txt(621); - - case JOB_NOVICE_HIGH: - case JOB_SWORDMAN_HIGH: - case JOB_MAGE_HIGH: - case JOB_ARCHER_HIGH: - case JOB_ACOLYTE_HIGH: - case JOB_MERCHANT_HIGH: - case JOB_THIEF_HIGH: - return msg_txt(575 - JOB_NOVICE_HIGH+class_); - - case JOB_LORD_KNIGHT: - case JOB_HIGH_PRIEST: - case JOB_HIGH_WIZARD: - case JOB_WHITESMITH: - case JOB_SNIPER: - case JOB_ASSASSIN_CROSS: - return msg_txt(582 - JOB_LORD_KNIGHT+class_); - - case JOB_LORD_KNIGHT2: - return msg_txt(582); - - case JOB_PALADIN: - case JOB_CHAMPION: - case JOB_PROFESSOR: - case JOB_STALKER: - case JOB_CREATOR: - case JOB_CLOWN: - case JOB_GYPSY: - return msg_txt(588 - JOB_PALADIN + class_); - - case JOB_PALADIN2: - return msg_txt(588); - - case JOB_BABY: - case JOB_BABY_SWORDMAN: - case JOB_BABY_MAGE: - case JOB_BABY_ARCHER: - case JOB_BABY_ACOLYTE: - case JOB_BABY_MERCHANT: - case JOB_BABY_THIEF: - return msg_txt(595 - JOB_BABY + class_); - - case JOB_BABY_KNIGHT: - case JOB_BABY_PRIEST: - case JOB_BABY_WIZARD: - case JOB_BABY_BLACKSMITH: - case JOB_BABY_HUNTER: - case JOB_BABY_ASSASSIN: - return msg_txt(602 - JOB_BABY_KNIGHT + class_); - - case JOB_BABY_KNIGHT2: - return msg_txt(602); - - case JOB_BABY_CRUSADER: - case JOB_BABY_MONK: - case JOB_BABY_SAGE: - case JOB_BABY_ROGUE: - case JOB_BABY_ALCHEMIST: - case JOB_BABY_BARD: - case JOB_BABY_DANCER: - return msg_txt(608 - JOB_BABY_CRUSADER + class_); - - case JOB_BABY_CRUSADER2: - return msg_txt(608); - - case JOB_SUPER_BABY: - return msg_txt(615); - - case JOB_TAEKWON: - return msg_txt(616); - case JOB_STAR_GLADIATOR: - case JOB_STAR_GLADIATOR2: - return msg_txt(617); - case JOB_SOUL_LINKER: - return msg_txt(618); - - case JOB_GANGSI: - case JOB_DEATH_KNIGHT: - case JOB_DARK_COLLECTOR: - return msg_txt(622 - JOB_GANGSI+class_); - - case JOB_RUNE_KNIGHT: - case JOB_WARLOCK: - case JOB_RANGER: - case JOB_ARCH_BISHOP: - case JOB_MECHANIC: - case JOB_GUILLOTINE_CROSS: - return msg_txt(625 - JOB_RUNE_KNIGHT+class_); - - case JOB_RUNE_KNIGHT_T: - case JOB_WARLOCK_T: - case JOB_RANGER_T: - case JOB_ARCH_BISHOP_T: - case JOB_MECHANIC_T: - case JOB_GUILLOTINE_CROSS_T: - return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); - - case JOB_ROYAL_GUARD: - case JOB_SORCERER: - case JOB_MINSTREL: - case JOB_WANDERER: - case JOB_SURA: - case JOB_GENETIC: - case JOB_SHADOW_CHASER: - return msg_txt(631 - JOB_ROYAL_GUARD+class_); - - case JOB_ROYAL_GUARD_T: - case JOB_SORCERER_T: - case JOB_MINSTREL_T: - case JOB_WANDERER_T: - case JOB_SURA_T: - case JOB_GENETIC_T: - case JOB_SHADOW_CHASER_T: - return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); - - case JOB_RUNE_KNIGHT2: - case JOB_RUNE_KNIGHT_T2: - return msg_txt(625); - - case JOB_ROYAL_GUARD2: - case JOB_ROYAL_GUARD_T2: - return msg_txt(631); - - case JOB_RANGER2: - case JOB_RANGER_T2: - return msg_txt(627); - - case JOB_MECHANIC2: - case JOB_MECHANIC_T2: - return msg_txt(629); - - case JOB_BABY_RUNE: - case JOB_BABY_WARLOCK: - case JOB_BABY_RANGER: - case JOB_BABY_BISHOP: - case JOB_BABY_MECHANIC: - case JOB_BABY_CROSS: - case JOB_BABY_GUARD: - case JOB_BABY_SORCERER: - case JOB_BABY_MINSTREL: - case JOB_BABY_WANDERER: - case JOB_BABY_SURA: - case JOB_BABY_GENETIC: - case JOB_BABY_CHASER: - return msg_txt(638 - JOB_BABY_RUNE+class_); - - case JOB_BABY_RUNE2: - return msg_txt(638); - - case JOB_BABY_GUARD2: - return msg_txt(644); - - case JOB_BABY_RANGER2: - return msg_txt(640); - - case JOB_BABY_MECHANIC2: - return msg_txt(642); - - case JOB_SUPER_NOVICE_E: - case JOB_SUPER_BABY_E: - return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); - - case JOB_KAGEROU: - case JOB_OBORO: - return msg_txt(653 - JOB_KAGEROU+class_); - - default: - return msg_txt(655); - } +const char *job_name(int class_) +{ + switch (class_) { + case JOB_NOVICE: + case JOB_SWORDMAN: + case JOB_MAGE: + case JOB_ARCHER: + case JOB_ACOLYTE: + case JOB_MERCHANT: + case JOB_THIEF: + return msg_txt(550 - JOB_NOVICE+class_); + + case JOB_KNIGHT: + case JOB_PRIEST: + case JOB_WIZARD: + case JOB_BLACKSMITH: + case JOB_HUNTER: + case JOB_ASSASSIN: + return msg_txt(557 - JOB_KNIGHT+class_); + + case JOB_KNIGHT2: + return msg_txt(557); + + case JOB_CRUSADER: + case JOB_MONK: + case JOB_SAGE: + case JOB_ROGUE: + case JOB_ALCHEMIST: + case JOB_BARD: + case JOB_DANCER: + return msg_txt(563 - JOB_CRUSADER+class_); + + case JOB_CRUSADER2: + return msg_txt(563); + + case JOB_WEDDING: + case JOB_SUPER_NOVICE: + case JOB_GUNSLINGER: + case JOB_NINJA: + case JOB_XMAS: + return msg_txt(570 - JOB_WEDDING+class_); + + case JOB_SUMMER: + return msg_txt(621); + + case JOB_NOVICE_HIGH: + case JOB_SWORDMAN_HIGH: + case JOB_MAGE_HIGH: + case JOB_ARCHER_HIGH: + case JOB_ACOLYTE_HIGH: + case JOB_MERCHANT_HIGH: + case JOB_THIEF_HIGH: + return msg_txt(575 - JOB_NOVICE_HIGH+class_); + + case JOB_LORD_KNIGHT: + case JOB_HIGH_PRIEST: + case JOB_HIGH_WIZARD: + case JOB_WHITESMITH: + case JOB_SNIPER: + case JOB_ASSASSIN_CROSS: + return msg_txt(582 - JOB_LORD_KNIGHT+class_); + + case JOB_LORD_KNIGHT2: + return msg_txt(582); + + case JOB_PALADIN: + case JOB_CHAMPION: + case JOB_PROFESSOR: + case JOB_STALKER: + case JOB_CREATOR: + case JOB_CLOWN: + case JOB_GYPSY: + return msg_txt(588 - JOB_PALADIN + class_); + + case JOB_PALADIN2: + return msg_txt(588); + + case JOB_BABY: + case JOB_BABY_SWORDMAN: + case JOB_BABY_MAGE: + case JOB_BABY_ARCHER: + case JOB_BABY_ACOLYTE: + case JOB_BABY_MERCHANT: + case JOB_BABY_THIEF: + return msg_txt(595 - JOB_BABY + class_); + + case JOB_BABY_KNIGHT: + case JOB_BABY_PRIEST: + case JOB_BABY_WIZARD: + case JOB_BABY_BLACKSMITH: + case JOB_BABY_HUNTER: + case JOB_BABY_ASSASSIN: + return msg_txt(602 - JOB_BABY_KNIGHT + class_); + + case JOB_BABY_KNIGHT2: + return msg_txt(602); + + case JOB_BABY_CRUSADER: + case JOB_BABY_MONK: + case JOB_BABY_SAGE: + case JOB_BABY_ROGUE: + case JOB_BABY_ALCHEMIST: + case JOB_BABY_BARD: + case JOB_BABY_DANCER: + return msg_txt(608 - JOB_BABY_CRUSADER + class_); + + case JOB_BABY_CRUSADER2: + return msg_txt(608); + + case JOB_SUPER_BABY: + return msg_txt(615); + + case JOB_TAEKWON: + return msg_txt(616); + case JOB_STAR_GLADIATOR: + case JOB_STAR_GLADIATOR2: + return msg_txt(617); + case JOB_SOUL_LINKER: + return msg_txt(618); + + case JOB_GANGSI: + case JOB_DEATH_KNIGHT: + case JOB_DARK_COLLECTOR: + return msg_txt(622 - JOB_GANGSI+class_); + + case JOB_RUNE_KNIGHT: + case JOB_WARLOCK: + case JOB_RANGER: + case JOB_ARCH_BISHOP: + case JOB_MECHANIC: + case JOB_GUILLOTINE_CROSS: + return msg_txt(625 - JOB_RUNE_KNIGHT+class_); + + case JOB_RUNE_KNIGHT_T: + case JOB_WARLOCK_T: + case JOB_RANGER_T: + case JOB_ARCH_BISHOP_T: + case JOB_MECHANIC_T: + case JOB_GUILLOTINE_CROSS_T: + return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); + + case JOB_ROYAL_GUARD: + case JOB_SORCERER: + case JOB_MINSTREL: + case JOB_WANDERER: + case JOB_SURA: + case JOB_GENETIC: + case JOB_SHADOW_CHASER: + return msg_txt(631 - JOB_ROYAL_GUARD+class_); + + case JOB_ROYAL_GUARD_T: + case JOB_SORCERER_T: + case JOB_MINSTREL_T: + case JOB_WANDERER_T: + case JOB_SURA_T: + case JOB_GENETIC_T: + case JOB_SHADOW_CHASER_T: + return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); + + case JOB_RUNE_KNIGHT2: + case JOB_RUNE_KNIGHT_T2: + return msg_txt(625); + + case JOB_ROYAL_GUARD2: + case JOB_ROYAL_GUARD_T2: + return msg_txt(631); + + case JOB_RANGER2: + case JOB_RANGER_T2: + return msg_txt(627); + + case JOB_MECHANIC2: + case JOB_MECHANIC_T2: + return msg_txt(629); + + case JOB_BABY_RUNE: + case JOB_BABY_WARLOCK: + case JOB_BABY_RANGER: + case JOB_BABY_BISHOP: + case JOB_BABY_MECHANIC: + case JOB_BABY_CROSS: + case JOB_BABY_GUARD: + case JOB_BABY_SORCERER: + case JOB_BABY_MINSTREL: + case JOB_BABY_WANDERER: + case JOB_BABY_SURA: + case JOB_BABY_GENETIC: + case JOB_BABY_CHASER: + return msg_txt(638 - JOB_BABY_RUNE+class_); + + case JOB_BABY_RUNE2: + return msg_txt(638); + + case JOB_BABY_GUARD2: + return msg_txt(644); + + case JOB_BABY_RANGER2: + return msg_txt(640); + + case JOB_BABY_MECHANIC2: + return msg_txt(642); + + case JOB_SUPER_NOVICE_E: + case JOB_SUPER_BABY_E: + return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); + + case JOB_KAGEROU: + case JOB_OBORO: + return msg_txt(653 - JOB_KAGEROU+class_); + + default: + return msg_txt(655); + } } /** * [Dekamaster/Nightroad] **/ -const char * geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", - "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", - "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", - "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", - "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", - "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", - "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", - "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", - "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", - "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", - "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", - "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", - "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", - "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", - "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", - "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", - "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", - "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", - "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", - "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", - "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", - "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", - "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", - "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", - "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", - "Saint Barthelemy","Saint Martin"}; +const char *geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", + "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", + "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", + "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", + "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", + "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", + "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", + "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", + "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", + "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", + "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", + "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", + "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", + "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", + "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", + "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", + "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", + "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", + "Saint Barthelemy","Saint Martin" + }; unsigned char *geoip_cache; -void geoip_readdb(void){ - struct stat bufa; - FILE *db=fopen("./db/GeoIP.dat","rb"); - fstat(fileno(db), &bufa); - geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); - if(fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { ShowError("geoip_cache reading didn't read all elements \n"); } - fclose(db); - ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); +void geoip_readdb(void) +{ + struct stat bufa; + FILE *db=fopen("./db/GeoIP.dat","rb"); + fstat(fileno(db), &bufa); + geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); + if (fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { + ShowError("geoip_cache reading didn't read all elements \n"); + } + fclose(db); + ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); } /* [Dekamaster/Nightroad] */ /* WHY NOT A DBMAP: There are millions of entries in GeoIP and it has its own algorithm to go quickly through them, a DBMap wouldn't be efficient */ -const char* geoip_getcountry(uint32 ipnum){ - int depth; - unsigned int x; - const unsigned char *buf; - unsigned int offset = 0; - - for (depth = 31; depth >= 0; depth--) { - buf = geoip_cache + (long)6 *offset; - if (ipnum & (1 << depth)) { - /* Take the right-hand branch */ - x = (buf[3*1 + 0] << (0*8)) - + (buf[3*1 + 1] << (1*8)) - + (buf[3*1 + 2] << (2*8)); - } else { - /* Take the left-hand branch */ - x = (buf[3*0 + 0] << (0*8)) - + (buf[3*0 + 1] << (1*8)) - + (buf[3*0 + 2] << (2*8)); - } - if (x >= 16776960) { - x=x-16776960; - return geoip_countryname[x]; - } - offset = x; - } - return geoip_countryname[0]; +const char *geoip_getcountry(uint32 ipnum) +{ + int depth; + unsigned int x; + const unsigned char *buf; + unsigned int offset = 0; + + for (depth = 31; depth >= 0; depth--) { + buf = geoip_cache + (long)6 *offset; + if (ipnum & (1 << depth)) { + /* Take the right-hand branch */ + x = (buf[3*1 + 0] << (0*8)) + + (buf[3*1 + 1] << (1*8)) + + (buf[3*1 + 2] << (2*8)); + } else { + /* Take the left-hand branch */ + x = (buf[3*0 + 0] << (0*8)) + + (buf[3*0 + 1] << (1*8)) + + (buf[3*0 + 2] << (2*8)); + } + if (x >= 16776960) { + x=x-16776960; + return geoip_countryname[x]; + } + offset = x; + } + return geoip_countryname[0]; } /* sends a mesasge to map server (fd) to a user (u_fd) although we use fd we keep aid for safe-check */ /* extremely handy I believe it will serve other uses in the near future */ -void inter_to_fd(int fd, int u_fd, int aid, char* msg, ...) { - char msg_out[512]; - va_list ap; - int len = 1;/* yes we start at 1 */ +void inter_to_fd(int fd, int u_fd, int aid, char *msg, ...) +{ + char msg_out[512]; + va_list ap; + int len = 1;/* yes we start at 1 */ - va_start(ap,msg); - len += vsnprintf(msg_out, 512, msg, ap); - va_end(ap); + va_start(ap,msg); + len += vsnprintf(msg_out, 512, msg, ap); + va_end(ap); - WFIFOHEAD(fd,12 + len); + WFIFOHEAD(fd,12 + len); - WFIFOW(fd,0) = 0x3807; - WFIFOW(fd,2) = 12 + (unsigned short)len; - WFIFOL(fd,4) = u_fd; - WFIFOL(fd,8) = aid; - safestrncpy((char*)WFIFOP(fd,12), msg_out, len); + WFIFOW(fd,0) = 0x3807; + WFIFOW(fd,2) = 12 + (unsigned short)len; + WFIFOL(fd,4) = u_fd; + WFIFOL(fd,8) = aid; + safestrncpy((char *)WFIFOP(fd,12), msg_out, len); - WFIFOSET(fd,12 + len); + WFIFOSET(fd,12 + len); - return; + return; } /* [Dekamaster/Nightroad] */ -void mapif_parse_accinfo(int fd) { - int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); - char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; - int account_id; - char *data; - - safestrncpy(query, (char*) RFIFOP(fd,14), NAME_LENGTH); - - Sql_EscapeString(sql_handle, query_esq, query); - - account_id = atoi(query); - - if (account_id < START_ACCOUNT_NUM) { // is string - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) - || Sql_NumRows(sql_handle) == 0 ) { - if( Sql_NumRows(sql_handle) == 0 ) { - inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); - } else { - Sql_ShowDebug(sql_handle); - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - } - Sql_FreeResult(sql_handle); - return; - } else { - if( Sql_NumRows(sql_handle) == 1 ) {//we found a perfect match - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_FreeResult(sql_handle); - } else {// more than one, listing... [Dekamaster/Nightroad] - inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); - while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - int class_; - short base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); job_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); - } - Sql_FreeResult(sql_handle); - return; - } - } - } - - /* it will only get here if we have a single match */ - if( account_id ) { - char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; - short level = -1; - int logincount = 0,state = 0; - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) - || Sql_NumRows(sql_handle) == 0 ) { - if( Sql_NumRows(sql_handle) == 0 ) { - inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id ); - } else { - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - } else { - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(userid, data, sizeof(userid)); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(user_pass, data, sizeof(user_pass)); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(email, data, sizeof(email)); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(last_ip, data, sizeof(last_ip)); - Sql_GetData(sql_handle, 4, &data, NULL); level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(lastlogin, data, sizeof(lastlogin)); - Sql_GetData(sql_handle, 6, &data, NULL); logincount = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); state = atoi(data); - } - - Sql_FreeResult(sql_handle); - - if (level == -1) - return; - - inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id ); - inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state ); - - if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ - inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass ); - - inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); - inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip)) ); - inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin ); - inter_to_fd(fd, u_fd, aid, "-- Character Details --" ); - - - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) - || Sql_NumRows(sql_handle) == 0 ) { - - if( Sql_NumRows(sql_handle) == 0 ) - inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); - else { - inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - - } else { - while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - int char_id, class_; - short char_num, base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); - } - } - Sql_FreeResult(sql_handle); - } - - return; +void mapif_parse_accinfo(int fd) +{ + int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); + char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; + int account_id; + char *data; + + safestrncpy(query, (char *) RFIFOP(fd,14), NAME_LENGTH); + + Sql_EscapeString(sql_handle, query_esq, query); + + account_id = atoi(query); + + if (account_id < START_ACCOUNT_NUM) { // is string + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) + || Sql_NumRows(sql_handle) == 0) { + if (Sql_NumRows(sql_handle) == 0) { + inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); + } else { + Sql_ShowDebug(sql_handle); + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + } + Sql_FreeResult(sql_handle); + return; + } else { + if (Sql_NumRows(sql_handle) == 1) { //we found a perfect match + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_FreeResult(sql_handle); + } else {// more than one, listing... [Dekamaster/Nightroad] + inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int class_; + short base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); + class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + job_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); + } + Sql_FreeResult(sql_handle); + return; + } + } + } + + /* it will only get here if we have a single match */ + if (account_id) { + char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; + short level = -1; + int logincount = 0,state = 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) + || Sql_NumRows(sql_handle) == 0) { + if (Sql_NumRows(sql_handle) == 0) { + inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id); + } else { + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + } else { + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + safestrncpy(userid, data, sizeof(userid)); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(user_pass, data, sizeof(user_pass)); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(email, data, sizeof(email)); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(last_ip, data, sizeof(last_ip)); + Sql_GetData(sql_handle, 4, &data, NULL); + level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(lastlogin, data, sizeof(lastlogin)); + Sql_GetData(sql_handle, 6, &data, NULL); + logincount = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + state = atoi(data); + } + + Sql_FreeResult(sql_handle); + + if (level == -1) + return; + + inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id); + inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state); + + if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ + inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass); + + inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); + inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip))); + inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin); + inter_to_fd(fd, u_fd, aid, "-- Character Details --"); + + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) + || Sql_NumRows(sql_handle) == 0) { + + if (Sql_NumRows(sql_handle) == 0) + inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); + else { + inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + + } else { + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int char_id, class_; + short char_num, base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); + char_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); + char_num = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + class_ = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + job_level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); + } + } + Sql_FreeResult(sql_handle); + } + + return; } //-------------------------------------------------------- // Save registry to sql -int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type) +int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type) { - struct global_reg* r; - StringBuf buf; - int i; - - if( account_id <= 0 ) - return 0; - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //Char Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - account_id = 0; - break; - case 2: //Account Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - char_id = 0; - break; - case 1: //Account2 Reg - ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_tosql: Invalid type %d\n", type); - return 0; - } - - if( reg->reg_num <= 0 ) - return 0; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); - - for( i = 0; i < reg->reg_num; ++i ) { - r = ®->reg[i]; - if( r->str[0] != '\0' && r->value[0] != '\0' ) { - char str[32]; - char val[256]; - - if( i > 0 ) - StringBuf_AppendStr(&buf, ","); - - Sql_EscapeString(sql_handle, str, r->str); - Sql_EscapeString(sql_handle, val, r->value); - - StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); - } - } - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - } - - StringBuf_Destroy(&buf); - - return 1; + struct global_reg *r; + StringBuf buf; + int i; + + if (account_id <= 0) + return 0; + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch (type) { + case 3: //Char Reg + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + account_id = 0; + break; + case 2: //Account Reg + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) + Sql_ShowDebug(sql_handle); + char_id = 0; + break; + case 1: //Account2 Reg + ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_tosql: Invalid type %d\n", type); + return 0; + } + + if (reg->reg_num <= 0) + return 0; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); + + for (i = 0; i < reg->reg_num; ++i) { + r = ®->reg[i]; + if (r->str[0] != '\0' && r->value[0] != '\0') { + char str[32]; + char val[256]; + + if (i > 0) + StringBuf_AppendStr(&buf, ","); + + Sql_EscapeString(sql_handle, str, r->str); + Sql_EscapeString(sql_handle, val, r->value); + + StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); + } + } + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + } + + StringBuf_Destroy(&buf); + + return 1; } // Load account_reg from sql (type=2) int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type) { - struct global_reg* r; - char* data; - size_t len; - int i; - - if( reg == NULL) - return 0; - - memset(reg, 0, sizeof(struct accreg)); - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //char reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - break; - case 2: //account reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - break; - case 1: //account2 reg - ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_fromsql: Invalid type %d\n", type); - return 0; - } - for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - r = ®->reg[i]; - // str - Sql_GetData(sql_handle, 0, &data, &len); - memcpy(r->str, data, min(len, sizeof(r->str))); - // value - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(r->value, data, min(len, sizeof(r->value))); - } - reg->reg_num = i; - Sql_FreeResult(sql_handle); - return 1; + struct global_reg *r; + char *data; + size_t len; + int i; + + if (reg == NULL) + return 0; + + memset(reg, 0, sizeof(struct accreg)); + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch (type) { + case 3: //char reg + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + break; + case 2: //account reg + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) + Sql_ShowDebug(sql_handle); + break; + case 1: //account2 reg + ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_fromsql: Invalid type %d\n", type); + return 0; + } + for (i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + r = ®->reg[i]; + // str + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(r->str, data, min(len, sizeof(r->str))); + // value + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(r->value, data, min(len, sizeof(r->value))); + } + reg->reg_num = i; + Sql_FreeResult(sql_handle); + return 1; } // Initialize int inter_accreg_sql_init(void) { - CREATE(accreg_pt, struct accreg, 1); - return 0; + CREATE(accreg_pt, struct accreg, 1); + return 0; } /*========================================== * read config file *------------------------------------------*/ -static int inter_config_read(const char* cfgName) +static int inter_config_read(const char *cfgName) { - int i; - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - fp = fopen(cfgName, "r"); - if(fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); - if(i != 2) - continue; - - if(!strcmpi(w1,"char_server_ip")) { - strcpy(char_server_ip,w2); - } else - if(!strcmpi(w1,"char_server_port")) { - char_server_port = atoi(w2); - } else - if(!strcmpi(w1,"char_server_id")) { - strcpy(char_server_id,w2); - } else - if(!strcmpi(w1,"char_server_pw")) { - strcpy(char_server_pw,w2); - } else - if(!strcmpi(w1,"char_server_db")) { - strcpy(char_server_db,w2); - } else - if(!strcmpi(w1,"default_codepage")) { - strcpy(default_codepage,w2); - } - else if(!strcmpi(w1,"party_share_level")) - party_share_level = atoi(w2); - else if(!strcmpi(w1,"log_inter")) - log_inter = atoi(w2); - else if(!strcmpi(w1,"main_chat_nick")) - safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); - else if(!strcmpi(w1,"import")) - inter_config_read(w2); - } - fclose(fp); - - ShowInfo ("Done reading %s.\n", cfgName); - - return 0; + int i; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); + if (i != 2) + continue; + + if (!strcmpi(w1,"char_server_ip")) { + strcpy(char_server_ip,w2); + } else if (!strcmpi(w1,"char_server_port")) { + char_server_port = atoi(w2); + } else if (!strcmpi(w1,"char_server_id")) { + strcpy(char_server_id,w2); + } else if (!strcmpi(w1,"char_server_pw")) { + strcpy(char_server_pw,w2); + } else if (!strcmpi(w1,"char_server_db")) { + strcpy(char_server_db,w2); + } else if (!strcmpi(w1,"default_codepage")) { + strcpy(default_codepage,w2); + } else if (!strcmpi(w1,"party_share_level")) + party_share_level = atoi(w2); + else if (!strcmpi(w1,"log_inter")) + log_inter = atoi(w2); + else if (!strcmpi(w1,"main_chat_nick")) + safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); + else if (!strcmpi(w1,"import")) + inter_config_read(w2); + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + + return 0; } // Save interlog into sql -int inter_log(char* fmt, ...) +int inter_log(char *fmt, ...) { - char str[255]; - char esc_str[sizeof(str)*2+1];// escaped str - va_list ap; + char str[255]; + char esc_str[sizeof(str)*2+1];// escaped str + va_list ap; - va_start(ap,fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); + va_start(ap,fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); - Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) - Sql_ShowDebug(sql_handle); + Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str)) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } // initialize int inter_init_sql(const char *file) { - //int i; - - inter_config_read(file); - - //DB connection initialized - sql_handle = Sql_Malloc(); - ShowInfo("Connect Character DB server.... (Character Server)\n"); - if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( *default_codepage ) { - if( SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage) ) - Sql_ShowDebug(sql_handle); - } - - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - inter_guild_sql_init(); - inter_storage_sql_init(); - inter_party_sql_init(); - inter_pet_sql_init(); - inter_homunculus_sql_init(); - inter_mercenary_sql_init(); - inter_elemental_sql_init(); - inter_accreg_sql_init(); - inter_mail_sql_init(); - inter_auction_sql_init(); - - geoip_readdb(); - msg_config_read("conf/msg_athena.conf"); - return 0; + //int i; + + inter_config_read(file); + + //DB connection initialized + sql_handle = Sql_Malloc(); + ShowInfo("Connect Character DB server.... (Character Server)\n"); + if (SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if (*default_codepage) { + if (SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage)) + Sql_ShowDebug(sql_handle); + } + + wis_db = idb_alloc(DB_OPT_RELEASE_DATA); + inter_guild_sql_init(); + inter_storage_sql_init(); + inter_party_sql_init(); + inter_pet_sql_init(); + inter_homunculus_sql_init(); + inter_mercenary_sql_init(); + inter_elemental_sql_init(); + inter_accreg_sql_init(); + inter_mail_sql_init(); + inter_auction_sql_init(); + + geoip_readdb(); + msg_config_read("conf/msg_athena.conf"); + return 0; } // finalize void inter_final(void) { - wis_db->destroy(wis_db, NULL); - - inter_guild_sql_final(); - inter_storage_sql_final(); - inter_party_sql_final(); - inter_pet_sql_final(); - inter_homunculus_sql_final(); - inter_mercenary_sql_final(); - inter_elemental_sql_final(); - inter_mail_sql_final(); - inter_auction_sql_final(); - - if (accreg_pt) aFree(accreg_pt); - - do_final_msg(); - return; + wis_db->destroy(wis_db, NULL); + + inter_guild_sql_final(); + inter_storage_sql_final(); + inter_party_sql_final(); + inter_pet_sql_final(); + inter_homunculus_sql_final(); + inter_mercenary_sql_final(); + inter_elemental_sql_final(); + inter_mail_sql_final(); + inter_auction_sql_final(); + + if (accreg_pt) aFree(accreg_pt); + + do_final_msg(); + return; } int inter_mapif_init(int fd) { - return 0; + return 0; } @@ -827,99 +849,98 @@ int inter_mapif_init(int fd) // broadcast sending int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, int sfd) { - unsigned char *buf = (unsigned char*)aMalloc((len)*sizeof(unsigned char)); - - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = fontColor; - WBUFW(buf,8) = fontType; - WBUFW(buf,10) = fontSize; - WBUFW(buf,12) = fontAlign; - WBUFW(buf,14) = fontY; - memcpy(WBUFP(buf,16), mes, len - 16); - mapif_sendallwos(sfd, buf, len); - - if (buf) - aFree(buf); - return 0; + unsigned char *buf = (unsigned char *)aMalloc((len)*sizeof(unsigned char)); + + WBUFW(buf,0) = 0x3800; + WBUFW(buf,2) = len; + WBUFL(buf,4) = fontColor; + WBUFW(buf,8) = fontType; + WBUFW(buf,10) = fontSize; + WBUFW(buf,12) = fontAlign; + WBUFW(buf,14) = fontY; + memcpy(WBUFP(buf,16), mes, len - 16); + mapif_sendallwos(sfd, buf, len); + + if (buf) + aFree(buf); + return 0; } // Wis sending int mapif_wis_message(struct WisData *wd) { - unsigned char buf[2048]; - if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 +wd->len; - WBUFL(buf, 4) = wd->id; - memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); - memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); - memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf,WBUFW(buf,2)); - - return 0; + unsigned char buf[2048]; + if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] + + WBUFW(buf, 0) = 0x3801; + WBUFW(buf, 2) = 56 +wd->len; + WBUFL(buf, 4) = wd->id; + memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); + memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); + memcpy(WBUFP(buf,56), wd->msg, wd->len); + wd->count = mapif_sendall(buf,WBUFW(buf,2)); + + return 0; } // Wis sending result int mapif_wis_end(struct WisData *wd, int flag) { - unsigned char buf[27]; + unsigned char buf[27]; - WBUFW(buf, 0)=0x3802; - memcpy(WBUFP(buf, 2),wd->src,24); - WBUFB(buf,26)=flag; - mapif_send(wd->fd,buf,27); - return 0; + WBUFW(buf, 0)=0x3802; + memcpy(WBUFP(buf, 2),wd->src,24); + WBUFB(buf,26)=flag; + mapif_send(wd->fd,buf,27); + return 0; } // Account registry transfer to map-server static void mapif_account_reg(int fd, unsigned char *src) { - WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO - mapif_sendallwos(fd, src, WBUFW(src,2)); + WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO + mapif_sendallwos(fd, src, WBUFW(src,2)); } // Send the requested account_reg int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) { - struct accreg *reg=accreg_pt; - WFIFOHEAD(fd, 13 + 5000); - inter_accreg_fromsql(account_id,char_id,reg,type); - - WFIFOW(fd,0)=0x3804; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=char_id; - WFIFOB(fd,12)=type; - if(reg->reg_num==0){ - WFIFOW(fd,2)=13; - }else{ - int i,p; - for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; - } - WFIFOW(fd,2)=p; - if (p>= 5000) - ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; + struct accreg *reg=accreg_pt; + WFIFOHEAD(fd, 13 + 5000); + inter_accreg_fromsql(account_id,char_id,reg,type); + + WFIFOW(fd,0)=0x3804; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=char_id; + WFIFOB(fd,12)=type; + if (reg->reg_num==0) { + WFIFOW(fd,2)=13; + } else { + int i,p; + for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { + p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. + p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; + } + WFIFOW(fd,2)=p; + if (p>= 5000) + ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); + } + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; } //Request to kick char from a certain map server. [Skotlex] int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) { - if (fd >= 0) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - return 0; - } - return -1; + if (fd >= 0) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b1f; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = reason; + WFIFOSET(fd,7); + return 0; + } + return -1; } //-------------------------------------------------------- @@ -930,34 +951,34 @@ int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) */ int check_ttl_wisdata_sub(DBKey key, DBData *data, va_list ap) { - unsigned long tick; - struct WisData *wd = db_data2ptr(data); - tick = va_arg(ap, unsigned long); + unsigned long tick; + struct WisData *wd = db_data2ptr(data); + tick = va_arg(ap, unsigned long); - if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; + if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) + wis_dellist[wis_delnum++] = wd->id; - return 0; + return 0; } int check_ttl_wisdata(void) { - unsigned long tick = gettick(); - int i; - - do { - wis_delnum = 0; - wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); - for(i = 0; i < wis_delnum; i++) { - struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); - ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, wd->id); - } - } while(wis_delnum >= WISDELLIST_MAX); - - return 0; + unsigned long tick = gettick(); + int i; + + do { + wis_delnum = 0; + wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); + for (i = 0; i < wis_delnum; i++) { + struct WisData *wd = (struct WisData *)idb_get(wis_db, wis_dellist[i]); + ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); + // removed. not send information after a timeout. Just no answer for the player + //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, wd->id); + } + } while (wis_delnum >= WISDELLIST_MAX); + + return 0; } //-------------------------------------------------------- @@ -965,209 +986,206 @@ int check_ttl_wisdata(void) // broadcast sending int mapif_parse_broadcast(int fd) { - mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); - return 0; + mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); + return 0; } // Wisp/page request to send int mapif_parse_WisRequest(int fd) { - struct WisData* wd; - static int wisid = 0; - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1];// escaped name - char* data; - size_t len; - - - if ( fd <= 0 ) {return 0;} // check if we have a valid fd - - if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { - ShowWarning("inter: Wis message size too long.\n"); - return 0; - } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... - ShowError("inter: Wis message doesn't exist.\n"); - return 0; - } - - safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - - // search if character exists before to ask all map-servers - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - {// Character exists. So, ask all map-servers - // to be sure of the correct name, rewrite it - Sql_GetData(sql_handle, 0, &data, &len); - memset(name, 0, NAME_LENGTH); - memcpy(name, data, min(len, NAME_LENGTH)); - // if source is destination, don't ask other servers. - if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) - { - uint8 buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - { - - CREATE(wd, struct WisData, 1); - - // Whether the failure of previous wisp/page transmission (timeout) - check_ttl_wisdata(); - - wd->id = ++wisid; - wd->fd = fd; - wd->len= RFIFOW(fd,2)-52; - memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); - memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); - memcpy(wd->msg, RFIFOP(fd,52), wd->len); - wd->tick = gettick(); - idb_put(wis_db, wd->id, wd); - mapif_wis_message(wd); - } - } - - Sql_FreeResult(sql_handle); - return 0; + struct WisData *wd; + static int wisid = 0; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1];// escaped name + char *data; + size_t len; + + + if (fd <= 0) { + return 0; // check if we have a valid fd + } + + if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { + ShowWarning("inter: Wis message size too long.\n"); + return 0; + } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... + ShowError("inter: Wis message doesn't exist.\n"); + return 0; + } + + safestrncpy(name, (char *)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + + // search if character exists before to ask all map-servers + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + unsigned char buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } else { + // Character exists. So, ask all map-servers + // to be sure of the correct name, rewrite it + Sql_GetData(sql_handle, 0, &data, &len); + memset(name, 0, NAME_LENGTH); + memcpy(name, data, min(len, NAME_LENGTH)); + // if source is destination, don't ask other servers. + if (strncmp((const char *)RFIFOP(fd,4), name, NAME_LENGTH) == 0) { + uint8 buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } else { + + CREATE(wd, struct WisData, 1); + + // Whether the failure of previous wisp/page transmission (timeout) + check_ttl_wisdata(); + + wd->id = ++wisid; + wd->fd = fd; + wd->len= RFIFOW(fd,2)-52; + memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); + memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); + memcpy(wd->msg, RFIFOP(fd,52), wd->len); + wd->tick = gettick(); + idb_put(wis_db, wd->id, wd); + mapif_wis_message(wd); + } + } + + Sql_FreeResult(sql_handle); + return 0; } // Wisp/page transmission result int mapif_parse_WisReply(int fd) { - int id, flag; - struct WisData *wd; + int id, flag; + struct WisData *wd; - id = RFIFOL(fd,2); - flag = RFIFOB(fd,6); - wd = (struct WisData*)idb_get(wis_db, id); - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server + id = RFIFOL(fd,2); + flag = RFIFOB(fd,6); + wd = (struct WisData *)idb_get(wis_db, id); + if (wd == NULL) + return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server - if ((--wd->count) <= 0 || flag != 1) { - mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, id); - } + if ((--wd->count) <= 0 || flag != 1) { + mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, id); + } - return 0; + return 0; } // Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) int mapif_parse_WisToGM(int fd) { - unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B + unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); + memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf, 0) = 0x3803; + mapif_sendall(buf, RFIFOW(fd,2)); - return 0; + return 0; } // Save account_reg into sql (type=2) int mapif_parse_Registry(int fd) { - int j,p,len, max; - struct accreg *reg=accreg_pt; - - memset(accreg_pt,0,sizeof(struct accreg)); - switch (RFIFOB(fd, 12)) { - case 3: //Character registry - max = GLOBAL_REG_NUM; - break; - case 2: //Account Registry - max = ACCOUNT_REG_NUM; - break; - case 1: //Account2 registry, must be sent over to login server. - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: - return 1; - } - for(j=0,p=13;jreg[j].str,&len); - reg->reg[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); - reg->reg[j].value[len]='\0'; - p +=len+1; - } - reg->reg_num=j; - - inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); - mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. - return 0; + int j,p,len, max; + struct accreg *reg=accreg_pt; + + memset(accreg_pt,0,sizeof(struct accreg)); + switch (RFIFOB(fd, 12)) { + case 3: //Character registry + max = GLOBAL_REG_NUM; + break; + case 2: //Account Registry + max = ACCOUNT_REG_NUM; + break; + case 1: //Account2 registry, must be sent over to login server. + return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); + default: + return 1; + } + for (j=0,p=13; jreg[j].str,&len); + reg->reg[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char *)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); + reg->reg[j].value[len]='\0'; + p +=len+1; + } + reg->reg_num=j; + + inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); + mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. + return 0; } // Request the value of all registries. int mapif_parse_RegistryRequest(int fd) { - //Load Char Registry - if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); - //Load Account Registry - if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); - //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); - return 1; + //Load Char Registry + if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); + //Load Account Registry + if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); + //Ask Login Server for Account2 values. + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); + return 1; } static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name) { - WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) = 0x3806; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = type; - WFIFOB(fd,11) = flag; - memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+13); + WFIFOHEAD(fd, NAME_LENGTH+13); + WFIFOW(fd, 0) = 0x3806; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = type; + WFIFOB(fd,11) = flag; + memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+13); } int mapif_parse_NameChangeRequest(int fd) { - int account_id, char_id, type; - char* name; - int i; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - type = RFIFOB(fd,10); - name = (char*)RFIFOP(fd,11); - - // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } - //TODO: type holds the type of object to rename. - //If it were a player, it needs to have the guild information and db information - //updated here, because changing it on the map won't make it be saved [Skotlex] - - //name allowed. - mapif_namechange_ack(fd, account_id, char_id, type, 1, name); - return 0; + int account_id, char_id, type; + char *name; + int i; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + type = RFIFOB(fd,10); + name = (char *)RFIFOP(fd,11); + + // Check Authorised letters/symbols in the name + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } + //TODO: type holds the type of object to rename. + //If it were a player, it needs to have the guild information and db information + //updated here, because changing it on the map won't make it be saved [Skotlex] + + //name allowed. + mapif_namechange_ack(fd, account_id, char_id, type, 1, name); + return 0; } //-------------------------------------------------------- @@ -1178,59 +1196,75 @@ int mapif_parse_NameChangeRequest(int fd) /// @param length The minimum allowed length, or -1 for dynamic lookup int inter_check_length(int fd, int length) { - if( length == -1 ) - {// variable-length packet - if( RFIFOREST(fd) < 4 ) - return 0; - length = RFIFOW(fd,2); - } + if (length == -1) { + // variable-length packet + if (RFIFOREST(fd) < 4) + return 0; + length = RFIFOW(fd,2); + } - if( (int)RFIFOREST(fd) < length ) - return 0; + if ((int)RFIFOREST(fd) < length) + return 0; - return length; + return length; } int inter_parse_frommap(int fd) { - int cmd; - int len = 0; - cmd = RFIFOW(fd,0); - // Check is valid packet entry - if(cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) - return 0; - - // Check packet length - if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch(cmd) { - case 0x3000: mapif_parse_broadcast(fd); break; - case 0x3001: mapif_parse_WisRequest(fd); break; - case 0x3002: mapif_parse_WisReply(fd); break; - case 0x3003: mapif_parse_WisToGM(fd); break; - case 0x3004: mapif_parse_Registry(fd); break; - case 0x3005: mapif_parse_RegistryRequest(fd); break; - case 0x3006: mapif_parse_NameChangeRequest(fd); break; - case 0x3007: mapif_parse_accinfo(fd); break; - /* 0x3008 is used by the report stuff */ - default: - if( inter_party_parse_frommap(fd) - || inter_guild_parse_frommap(fd) - || inter_storage_parse_frommap(fd) - || inter_pet_parse_frommap(fd) - || inter_homunculus_parse_frommap(fd) - || inter_mercenary_parse_frommap(fd) - || inter_elemental_parse_frommap(fd) - || inter_mail_parse_frommap(fd) - || inter_auction_parse_frommap(fd) - || inter_quest_parse_frommap(fd) - ) - break; - else - return 0; - } - - RFIFOSKIP(fd, len); - return 1; + int cmd; + int len = 0; + cmd = RFIFOW(fd,0); + // Check is valid packet entry + if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) + return 0; + + // Check packet length + if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) + return 2; + + switch (cmd) { + case 0x3000: + mapif_parse_broadcast(fd); + break; + case 0x3001: + mapif_parse_WisRequest(fd); + break; + case 0x3002: + mapif_parse_WisReply(fd); + break; + case 0x3003: + mapif_parse_WisToGM(fd); + break; + case 0x3004: + mapif_parse_Registry(fd); + break; + case 0x3005: + mapif_parse_RegistryRequest(fd); + break; + case 0x3006: + mapif_parse_NameChangeRequest(fd); + break; + case 0x3007: + mapif_parse_accinfo(fd); + break; + /* 0x3008 is used by the report stuff */ + default: + if (inter_party_parse_frommap(fd) + || inter_guild_parse_frommap(fd) + || inter_storage_parse_frommap(fd) + || inter_pet_parse_frommap(fd) + || inter_homunculus_parse_frommap(fd) + || inter_mercenary_parse_frommap(fd) + || inter_elemental_parse_frommap(fd) + || inter_mail_parse_frommap(fd) + || inter_auction_parse_frommap(fd) + || inter_quest_parse_frommap(fd) + ) + break; + else + return 0; + } + + RFIFOSKIP(fd, len); + return 1; } diff --git a/src/char/inter.h b/src/char/inter.h index ac2e1785f..199d70bb4 100644 --- a/src/char/inter.h +++ b/src/char/inter.h @@ -20,8 +20,8 @@ int inter_log(char *fmt,...); extern unsigned int party_share_level; -extern Sql* sql_handle; -extern Sql* lsql_handle; +extern Sql *sql_handle; +extern Sql *lsql_handle; extern char main_chat_nick[16]; diff --git a/src/common/atomic.h b/src/common/atomic.h index b1a4bda92..a7e953db2 100644 --- a/src/common/atomic.h +++ b/src/common/atomic.h @@ -4,16 +4,16 @@ #ifndef _rA_ATOMIC_H_ #define _rA_ATOMIC_H_ -// Atomic Operations +// Atomic Operations // (Interlocked CompareExchange, Add .. and so on ..) -// +// // Implementation varies / depends on: -// - Architecture -// - Compiler -// - Operating System +// - Architecture +// - Compiler +// - Operating System // // our Abstraction is fully API-Compatible to Microsofts implementation @ NT5.0+ -// +// #include "../common/cbasetypes.h" #if defined(_MSC_VER) @@ -22,60 +22,65 @@ #if !defined(_M_X64) // When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft // (because they need at least i586 so its not generic enough.. ... ) -forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){ - _asm{ - lea esi,_cmp; - lea edi,exch; - - mov eax,[esi]; - mov edx,4[esi]; - mov ebx,[edi]; - mov ecx,4[edi]; - mov esi,dest; - - lock CMPXCHG8B [esi]; - } +forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp) +{ + _asm { + lea esi,_cmp; + lea edi,exch; + + mov eax,[esi]; + mov edx,4[esi]; + mov ebx,[edi]; + mov ecx,4[edi]; + mov esi,dest; + + lock CMPXCHG8B [esi]; + } } -forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){ - __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old+1), old) != old); +forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend) +{ + __int64 old; + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old+1), old) != old); - return (old + 1); + return (old + 1); } -forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){ - __int64 old; +forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend) +{ + __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old-1), old) != old); + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old-1), old) != old); - return (old - 1); + return (old - 1); } -forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ - __int64 old; +forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) +{ + __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old + increment), old) != old); + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old + increment), old) != old); - return old; + return old; } -forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){ - __int64 old; - do{ - old = *target; - }while(InterlockedCompareExchange64(target, val, old) != old); +forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val) +{ + __int64 old; + do { + old = *target; + } while (InterlockedCompareExchange64(target, val, old) != old); - return old; + return old; } #endif //endif 32bit windows @@ -86,52 +91,62 @@ forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 v #error Your Target Platfrom is not supported #endif -static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ - return __sync_fetch_and_add(addend, increment); +static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) +{ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd64() -static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment){ - return __sync_fetch_and_add(addend, increment); +static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment) +{ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd() -static forceinline int64 InterlockedIncrement64(volatile int64 *addend){ - return __sync_add_and_fetch(addend, 1); +static forceinline int64 InterlockedIncrement64(volatile int64 *addend) +{ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement64() -static forceinline int32 InterlockedIncrement(volatile int32 *addend){ - return __sync_add_and_fetch(addend, 1); +static forceinline int32 InterlockedIncrement(volatile int32 *addend) +{ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement() -static forceinline int64 InterlockedDecrement64(volatile int64 *addend){ - return __sync_sub_and_fetch(addend, 1); +static forceinline int64 InterlockedDecrement64(volatile int64 *addend) +{ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement64() -static forceinline int32 InterlockedDecrement(volatile int32 *addend){ - return __sync_sub_and_fetch(addend, 1); +static forceinline int32 InterlockedDecrement(volatile int32 *addend) +{ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement() -static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp){ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp) +{ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchange64() -static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp){ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp) +{ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchnage() -static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val){ - return __sync_lock_test_and_set(target, val); +static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val) +{ + return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange64() -static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val){ +static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val) +{ return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange() diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 731a8b578..a47a7434f 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -59,11 +59,11 @@ // debug function name #ifndef __NETBSD__ #if __STDC_VERSION__ < 199901L -# if __GNUC__ >= 2 -# define __func__ __FUNCTION__ -# else -# define __func__ "" -# endif +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif #endif #endif @@ -106,56 +106,56 @@ // Integers with guaranteed _exact_ size. ////////////////////////////////////////////////////////////////////////// -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; -typedef int8_t sint8; -typedef int16_t sint16; -typedef int32_t sint32; -typedef int64_t sint64; +typedef int8_t sint8; +typedef int16_t sint16; +typedef int32_t sint32; +typedef int64_t sint64; -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; #undef UINT8_MIN #undef UINT16_MIN #undef UINT32_MIN #undef UINT64_MIN -#define UINT8_MIN ((uint8) UINT8_C(0x00)) -#define UINT16_MIN ((uint16)UINT16_C(0x0000)) -#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) -#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) +#define UINT8_MIN ((uint8) UINT8_C(0x00)) +#define UINT16_MIN ((uint16)UINT16_C(0x0000)) +#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) +#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) #undef UINT8_MAX #undef UINT16_MAX #undef UINT32_MAX #undef UINT64_MAX -#define UINT8_MAX ((uint8) UINT8_C(0xFF)) -#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) -#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) -#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) +#define UINT8_MAX ((uint8) UINT8_C(0xFF)) +#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) +#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) +#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) #undef SINT8_MIN #undef SINT16_MIN #undef SINT32_MIN #undef SINT64_MIN -#define SINT8_MIN ((sint8) INT8_C(0x80)) -#define SINT16_MIN ((sint16)INT16_C(0x8000)) -#define SINT32_MIN ((sint32)INT32_C(0x80000000)) -#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) +#define SINT8_MIN ((sint8) INT8_C(0x80)) +#define SINT16_MIN ((sint16)INT16_C(0x8000)) +#define SINT32_MIN ((sint32)INT32_C(0x80000000)) +#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) #undef SINT8_MAX #undef SINT16_MAX #undef SINT32_MAX #undef SINT64_MAX -#define SINT8_MAX ((sint8) INT8_C(0x7F)) -#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) -#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) -#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) +#define SINT8_MAX ((sint8) INT8_C(0x7F)) +#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) +#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) +#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) ////////////////////////////////////////////////////////////////////////// // Integers with guaranteed _minimum_ size. @@ -180,10 +180,10 @@ typedef unsigned long int ppuint32; #if defined(WIN32) && !defined(MINGW) // does not have a signed size_t ////////////////////////////// -#if defined(_WIN64) // naive 64bit windows platform -typedef __int64 ssize_t; +#if defined(_WIN64) // naive 64bit windows platform +typedef __int64 ssize_t; #else -typedef int ssize_t; +typedef int ssize_t; #endif ////////////////////////////// #endif @@ -201,23 +201,23 @@ typedef uintptr_t uintptr; // Add a 'sysint' Type which has the width of the platform we're compiled for. ////////////////////////////////////////////////////////////////////////// #if defined(__GNUC__) - #if defined(__x86_64__) - typedef int64 sysint; - typedef uint64 usysint; - #else - typedef int32 sysint; - typedef uint32 usysint; - #endif +#if defined(__x86_64__) +typedef int64 sysint; +typedef uint64 usysint; +#else +typedef int32 sysint; +typedef uint32 usysint; +#endif #elif defined(_MSC_VER) - #if defined(_M_X64) - typedef int64 sysint; - typedef uint64 usysint; - #else - typedef int32 sysint; - typedef uint32 usysint; - #endif +#if defined(_M_X64) +typedef int64 sysint; +typedef uint64 usysint; +#else +typedef int32 sysint; +typedef uint32 usysint; +#endif #else - #error Compiler / Platform is unsupported. +#error Compiler / Platform is unsupported. #endif @@ -225,21 +225,21 @@ typedef uintptr_t uintptr; // some redefine of function redefines for some Compilers ////////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) || defined(__BORLANDC__) -#define strcasecmp stricmp -#define strncasecmp strnicmp -#define strncmpi strnicmp -#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +#define strncmpi strnicmp +#define snprintf _snprintf #if defined(_MSC_VER) && _MSC_VER < 1400 -#define vsnprintf _vsnprintf +#define vsnprintf _vsnprintf #endif #else -#define strcmpi strcasecmp -#define stricmp strcasecmp -#define strncmpi strncasecmp -#define strnicmp strncasecmp +#define strcmpi strcasecmp +#define stricmp strcasecmp +#define strncmpi strncasecmp +#define strnicmp strncasecmp #endif #if defined(_MSC_VER) && _MSC_VER > 1200 -#define strtoull _strtoui64 +#define strtoull _strtoui64 #endif // keyword replacement @@ -262,8 +262,8 @@ typedef uintptr_t uintptr; // boolean types for C typedef char bool; -#define false (1==0) -#define true (1==1) +#define false (1==0) +#define true (1==1) ////////////////////////////// #endif // not __cplusplus @@ -276,7 +276,7 @@ typedef char bool; #undef swap #endif // hmm only ints? -//#define swap(a,b) { int temp=a; a=b; b=temp;} +//#define swap(a,b) { int temp=a; a=b; b=temp;} // if using macros then something that is type independent //#define swap(a,b) ((a == b) || ((a ^= b), (b ^= a), (a ^= b))) // Avoid "value computed is not used" warning and generates the same assembly code @@ -299,7 +299,7 @@ typedef char bool; ////////////////////////////////////////////////////////////////////////// // number of bits in a byte #ifndef NBBY -#define NBBY 8 +#define NBBY 8 #endif ////////////////////////////////////////////////////////////////////////// @@ -383,17 +383,20 @@ typedef char bool; // Set a pointer variable to a pointer value. #ifdef __cplusplus template -void SET_POINTER(T1*&var, T2* p) +void SET_POINTER(T1 *&var, T2 *p) { - var = static_cast(p); + var = static_cast(p); } template -void SET_FUNCPOINTER(T1& var, T2 p) +void SET_FUNCPOINTER(T1 &var, T2 p) { - char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void*) && sizeof(T2) == sizeof(void*)?1:-1];// 1 if true, -1 if false - union{ T1 out; T2 in; } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard - tmp.in = p; - var = tmp.out; + char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void *) && sizeof(T2) == sizeof(void *)?1:-1]; // 1 if true, -1 if false + union { + T1 out; + T2 in; + } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard + tmp.in = p; + var = tmp.out; } #else #define SET_POINTER(var,p) (var) = (p) diff --git a/src/common/conf.c b/src/common/conf.c index 3057bd4dc..2027b4b09 100644 --- a/src/common/conf.c +++ b/src/common/conf.c @@ -8,14 +8,14 @@ int conf_read_file(config_t *config, const char *config_filename) { - config_init(config); - if (!config_read_file(config, config_filename)) { - ShowError("%s:%d - %s\n", config_error_file(config), - config_error_line(config), config_error_text(config)); - config_destroy(config); - return 1; - } - return 0; + config_init(config); + if (!config_read_file(config, config_filename)) { + ShowError("%s:%d - %s\n", config_error_file(config), + config_error_line(config), config_error_text(config)); + config_destroy(config); + return 1; + } + return 0; } // @@ -28,82 +28,81 @@ int config_setting_copy(config_setting_t *parent, const config_setting_t *src); void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src) { - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } - else { - config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (set == NULL) - return; - - if (CONFIG_TYPE_INT == config_setting_type(src)) { - config_setting_set_int(set, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - config_setting_set_int64(set, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float(set, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string(set, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool(set, config_setting_get_bool(src)); - } - } + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } else { + config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (set == NULL) + return; + + if (CONFIG_TYPE_INT == config_setting_type(src)) { + config_setting_set_int(set, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + config_setting_set_int64(set, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float(set, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string(set, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool(set, config_setting_get_bool(src)); + } + } } void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *set = NULL; - - if (config_setting_is_aggregate(src)) - config_setting_copy_aggregate(parent, src); - else if (CONFIG_TYPE_INT == config_setting_type(src)) { - set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); - } + config_setting_t *set = NULL; + + if (config_setting_is_aggregate(src)) + config_setting_copy_aggregate(parent, src); + else if (CONFIG_TYPE_INT == config_setting_type(src)) { + set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); + } } void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *newAgg; - int i, n; - - newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (newAgg == NULL) - return; - - n = config_setting_length(src); - - for (i = 0; i < n; i++) { - if (config_setting_is_group(src)) { - config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); - } else { - config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); - } - } + config_setting_t *newAgg; + int i, n; + + newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (newAgg == NULL) + return; + + n = config_setting_length(src); + + for (i = 0; i < n; i++) { + if (config_setting_is_group(src)) { + config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); + } else { + config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); + } + } } int config_setting_copy(config_setting_t *parent, const config_setting_t *src) { - if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) - return CONFIG_FALSE; - - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } else { - config_setting_copy_simple(parent, src); - } - return CONFIG_TRUE; + if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) + return CONFIG_FALSE; + + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } else { + config_setting_copy_simple(parent, src); + } + return CONFIG_TRUE; } diff --git a/src/common/core.c b/src/common/core.c index e1f99885b..efab15dcb 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -28,7 +28,7 @@ void (*shutdown_callback)(void) = NULL; #if defined(BUILDBOT) - int buildbotflag = 0; +int buildbotflag = 0; #endif int runflag = CORE_ST_RUN; @@ -38,14 +38,14 @@ char **arg_v = NULL; char *SERVER_NAME = NULL; char SERVER_TYPE = ATHENA_SERVER_NONE; -#ifndef MINICORE // minimalist Core +#ifndef MINICORE // minimalist Core // Added by Gabuzomeu // // This is an implementation of signal() using sigaction() for portability. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced // Programming in the UNIX Environment_. // -#ifdef WIN32 // windows don't have SIGPIPE +#ifdef WIN32 // windows don't have SIGPIPE #define SIGPIPE SIGINT #endif @@ -54,229 +54,225 @@ char SERVER_TYPE = ATHENA_SERVER_NONE; #else sigfunc *compat_signal(int signo, sigfunc *func) { - struct sigaction sact, oact; + struct sigaction sact, oact; - sact.sa_handler = func; - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; #ifdef SA_INTERRUPT - sact.sa_flags |= SA_INTERRUPT; /* SunOS */ + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ #endif - if (sigaction(signo, &sact, &oact) < 0) - return (SIG_ERR); + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); - return (oact.sa_handler); + return (oact.sa_handler); } #endif /*====================================== - * CORE : Console events for Windows + * CORE : Console events for Windows *--------------------------------------*/ #ifdef _WIN32 static BOOL WINAPI console_handler(DWORD c_event) { - switch(c_event) - { - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - default: - return FALSE; + switch (c_event) { + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if (shutdown_callback != NULL) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + default: + return FALSE; } return TRUE; } static void cevents_init() { - if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) - ShowWarning ("Unable to install the console handler!\n"); + if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) + ShowWarning("Unable to install the console handler!\n"); } #endif /*====================================== - * CORE : Signal Sub Function + * CORE : Signal Sub Function *--------------------------------------*/ static void sig_proc(int sn) { - static int is_called = 0; - - switch (sn) { - case SIGINT: - case SIGTERM: - if (++is_called > 3) - exit(EXIT_SUCCESS); - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - case SIGSEGV: - case SIGFPE: - do_abort(); - // Pass the signal to the system's default handler - compat_signal(sn, SIG_DFL); - raise(sn); - break; + static int is_called = 0; + + switch (sn) { + case SIGINT: + case SIGTERM: + if (++is_called > 3) + exit(EXIT_SUCCESS); + if (shutdown_callback != NULL) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + case SIGSEGV: + case SIGFPE: + do_abort(); + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); + break; #ifndef _WIN32 - case SIGXFSZ: - // ignore and allow it to set errno to EFBIG - ShowWarning ("Max file size reached!\n"); - //run_flag = 0; // should we quit? - break; - case SIGPIPE: - //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c - break; // does nothing here + case SIGXFSZ: + // ignore and allow it to set errno to EFBIG + ShowWarning("Max file size reached!\n"); + //run_flag = 0; // should we quit? + break; + case SIGPIPE: + //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c + break; // does nothing here #endif - } + } } -void signals_init (void) +void signals_init(void) { - compat_signal(SIGTERM, sig_proc); - compat_signal(SIGINT, sig_proc); + compat_signal(SIGTERM, sig_proc); + compat_signal(SIGINT, sig_proc); #ifndef _DEBUG // need unhandled exceptions to debug on Windows - compat_signal(SIGSEGV, sig_proc); - compat_signal(SIGFPE, sig_proc); + compat_signal(SIGSEGV, sig_proc); + compat_signal(SIGFPE, sig_proc); #endif #ifndef _WIN32 - compat_signal(SIGILL, SIG_DFL); - compat_signal(SIGXFSZ, sig_proc); - compat_signal(SIGPIPE, sig_proc); - compat_signal(SIGBUS, SIG_DFL); - compat_signal(SIGTRAP, SIG_DFL); + compat_signal(SIGILL, SIG_DFL); + compat_signal(SIGXFSZ, sig_proc); + compat_signal(SIGPIPE, sig_proc); + compat_signal(SIGBUS, SIG_DFL); + compat_signal(SIGTRAP, SIG_DFL); #endif } #endif #ifdef SVNVERSION - const char *get_svn_revision(void) - { - return EXPAND_AND_QUOTE(SVNVERSION); - } +const char *get_svn_revision(void) +{ + return EXPAND_AND_QUOTE(SVNVERSION); +} #else// not SVNVERSION -const char* get_svn_revision(void) +const char *get_svn_revision(void) { - static char svn_version_buffer[16] = ""; - FILE *fp; - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - - // subversion 1.7 uses a sqlite3 database - // FIXME this is hackish at best... - // - ignores database file structure - // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" - // - since it's a cache column, the data might not even exist - if( (fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL ) - { - #ifndef SVNNODEPATH - //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up - #define SVNNODEPATH trunk - #endif - const char* prefix = "!svn/ver/"; - const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this - size_t prefix_len = strlen(prefix); - size_t postfix_len = strlen(postfix); - size_t i,j,len; - char* buffer; - - // read file to buffer - fseek(fp, 0, SEEK_END); - len = ftell(fp); - buffer = (char*)aMalloc(len + 1); - fseek(fp, 0, SEEK_SET); - len = fread(buffer, 1, len, fp); - buffer[len] = '\0'; - fclose(fp); - - // parse buffer - for( i = prefix_len + 1; i + postfix_len <= len; ++i ) - { - if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 ) - continue; // postfix missmatch - for( j = i; j > 0; --j ) - {// skip digits - if( !ISDIGIT(buffer[j - 1]) ) - break; - } - if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 ) - continue; // prefix missmatch - // done - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); - break; - } - aFree(buffer); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // subversion 1.6 and older? - if ((fp = fopen(".svn/entries", "r")) != NULL) - { - char line[1024]; - int rev; - // Check the version - if (fgets(line, sizeof(line), fp)) - { - if(!ISDIGIT(line[0])) - { - // XML File format - while (fgets(line,sizeof(line),fp)) - if (strstr(line,"revision=")) break; - if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); - } - } - else - { - // Bin File format - if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get bin name\n"); } // Get the name - if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get entries kind\n"); } // Get the entries kind - if(fgets(line, sizeof(line), fp)) // Get the rev numver - { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); - } - } - } - fclose(fp); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // fallback - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); - return svn_version_buffer; + static char svn_version_buffer[16] = ""; + FILE *fp; + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + + // subversion 1.7 uses a sqlite3 database + // FIXME this is hackish at best... + // - ignores database file structure + // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" + // - since it's a cache column, the data might not even exist + if ((fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL) { +#ifndef SVNNODEPATH + //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up +#define SVNNODEPATH trunk +#endif + const char *prefix = "!svn/ver/"; + const char *postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this + size_t prefix_len = strlen(prefix); + size_t postfix_len = strlen(postfix); + size_t i,j,len; + char *buffer; + + // read file to buffer + fseek(fp, 0, SEEK_END); + len = ftell(fp); + buffer = (char *)aMalloc(len + 1); + fseek(fp, 0, SEEK_SET); + len = fread(buffer, 1, len, fp); + buffer[len] = '\0'; + fclose(fp); + + // parse buffer + for (i = prefix_len + 1; i + postfix_len <= len; ++i) { + if (buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0) + continue; // postfix missmatch + for (j = i; j > 0; --j) { + // skip digits + if (!ISDIGIT(buffer[j - 1])) + break; + } + if (memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0) + continue; // prefix missmatch + // done + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); + break; + } + aFree(buffer); + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + } + + // subversion 1.6 and older? + if ((fp = fopen(".svn/entries", "r")) != NULL) { + char line[1024]; + int rev; + // Check the version + if (fgets(line, sizeof(line), fp)) { + if (!ISDIGIT(line[0])) { + // XML File format + while (fgets(line,sizeof(line),fp)) + if (strstr(line,"revision=")) break; + if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); + } + } else { + // Bin File format + if (fgets(line, sizeof(line), fp) == NULL) { + printf("Can't get bin name\n"); // Get the name + } + if (fgets(line, sizeof(line), fp) == NULL) { + printf("Can't get entries kind\n"); // Get the entries kind + } + if (fgets(line, sizeof(line), fp)) { // Get the rev numver + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); + } + } + } + fclose(fp); + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + } + + // fallback + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); + return svn_version_buffer; } #endif /*====================================== - * CORE : Display title + * CORE : Display title * ASCII By CalciumKid 1/12/2011 *--------------------------------------*/ -static void display_title(void) { - //ClearScreen(); // clear screen and go up/left (0, 0 position in text) - - ShowMessage("\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - - ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); +static void display_title(void) +{ + //ClearScreen(); // clear screen and go up/left (0, 0 position in text) + + ShowMessage("\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + + ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); } // Warning if executed as superuser (root) @@ -284,72 +280,73 @@ void usercheck(void) { #ifndef _WIN32 if (geteuid() == 0) { - ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n"); + ShowWarning("You are running rAthena with root privileges, it is not necessary.\n"); } #endif } /*====================================== - * CORE : MAINROUTINE + * CORE : MAINROUTINE *--------------------------------------*/ -int main (int argc, char **argv) +int main(int argc, char **argv) { - {// initialize program arguments - char *p1 = SERVER_NAME = argv[0]; - char *p2 = p1; - while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) - { - SERVER_NAME = ++p1; - p2 = p1; - } - arg_c = argc; - arg_v = argv; - } - - malloc_init();// needed for Show* in display_title() [FlavioJS] + { + // initialize program arguments + char *p1 = SERVER_NAME = argv[0]; + char *p2 = p1; + while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) { + SERVER_NAME = ++p1; + p2 = p1; + } + arg_c = argc; + arg_v = argv; + } + + malloc_init();// needed for Show* in display_title() [FlavioJS] #ifdef MINICORE // minimalist Core - display_title(); - usercheck(); - do_init(argc,argv); - do_final(); + display_title(); + usercheck(); + do_init(argc,argv); + do_final(); #else// not MINICORE - set_server_type(); - display_title(); - usercheck(); + set_server_type(); + display_title(); + usercheck(); - rathread_init(); - mempool_init(); - db_init(); - signals_init(); + rathread_init(); + mempool_init(); + db_init(); + signals_init(); #ifdef _WIN32 - cevents_init(); + cevents_init(); #endif - timer_init(); - socket_init(); + timer_init(); + socket_init(); - do_init(argc,argv); + do_init(argc,argv); - {// Main runtime cycle - int next; - while (runflag != CORE_ST_STOP) { - next = do_timer(gettick_nocache()); - do_sockets(next); - } - } + { + // Main runtime cycle + int next; + while (runflag != CORE_ST_STOP) { + next = do_timer(gettick_nocache()); + do_sockets(next); + } + } - do_final(); + do_final(); - timer_final(); - socket_final(); - db_final(); - mempool_final(); - rathread_final(); + timer_final(); + socket_final(); + db_final(); + mempool_final(); + rathread_final(); #endif - malloc_final(); + malloc_final(); - return 0; + return 0; } diff --git a/src/common/core.h b/src/common/core.h index d48962c94..d12723445 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -1,14 +1,14 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _CORE_H_ -#define _CORE_H_ +#ifndef _CORE_H_ +#define _CORE_H_ extern int arg_c; extern char **arg_v; #if defined(BUILDBOT) - extern int buildbotflag; +extern int buildbotflag; #endif /// @see E_CORE_ST @@ -16,28 +16,27 @@ extern int runflag; extern char *SERVER_NAME; enum { - ATHENA_SERVER_NONE = 0, // not defined - ATHENA_SERVER_LOGIN = 1, // login server - ATHENA_SERVER_CHAR = 2, // char server - ATHENA_SERVER_INTER = 4, // inter server - ATHENA_SERVER_MAP = 8, // map server + ATHENA_SERVER_NONE = 0, // not defined + ATHENA_SERVER_LOGIN = 1, // login server + ATHENA_SERVER_CHAR = 2, // char server + ATHENA_SERVER_INTER = 4, // inter server + ATHENA_SERVER_MAP = 8, // map server }; extern char SERVER_TYPE; -extern int parse_console(const char* buf); +extern int parse_console(const char *buf); extern const char *get_svn_revision(void); -extern int do_init(int,char**); +extern int do_init(int,char **); extern void set_server_type(void); extern void do_abort(void); extern void do_final(void); /// The main loop continues until runflag is CORE_ST_STOP -enum E_CORE_ST -{ - CORE_ST_STOP = 0, - CORE_ST_RUN, - CORE_ST_LAST +enum E_CORE_ST { + CORE_ST_STOP = 0, + CORE_ST_RUN, + CORE_ST_LAST }; /// Called when a terminate signal is received. (Ctrl+C pressed) diff --git a/src/common/db.c b/src/common/db.c index 204c6d2ea..c5db21a02 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -88,7 +88,7 @@ \*****************************************************************************/ /** - * If defined statistics about database nodes, database creating/destruction + * If defined statistics about database nodes, database creating/destruction * and function usage are keept and displayed when finalizing the database * system. * WARNING: This adds overhead to every database operation (not shure how much). @@ -112,8 +112,8 @@ * @see struct dbn */ typedef enum node_color { - RED, - BLACK + RED, + BLACK } node_color; /** @@ -129,16 +129,16 @@ typedef enum node_color { * @see DBMap_impl#ht */ typedef struct dbn { - // Tree structure - struct dbn *parent; - struct dbn *left; - struct dbn *right; - // Node data - DBKey key; - DBData data; - // Other - node_color color; - unsigned deleted : 1; + // Tree structure + struct dbn *parent; + struct dbn *left; + struct dbn *right; + // Node data + DBKey key; + DBData data; + // Other + node_color color; + unsigned deleted : 1; } *DBNode; /** @@ -149,8 +149,8 @@ typedef struct dbn { * @see DBMap_impl#free_list */ struct db_free { - DBNode node; - DBNode *root; + DBNode node; + DBNode *root; }; /** @@ -176,28 +176,28 @@ struct db_free { * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short) */ typedef struct DBMap_impl { - // Database interface - struct DBMap vtable; - // File and line of allocation - const char *alloc_file; - int alloc_line; - // Lock system - struct db_free *free_list; - unsigned int free_count; - unsigned int free_max; - unsigned int free_lock; - // Other - ERS nodes; - DBComparator cmp; - DBHasher hash; - DBReleaser release; - DBNode ht[HASH_SIZE]; - DBNode cache; - DBType type; - DBOptions options; - uint32 item_count; - unsigned short maxlen; - unsigned global_lock : 1; + // Database interface + struct DBMap vtable; + // File and line of allocation + const char *alloc_file; + int alloc_line; + // Lock system + struct db_free *free_list; + unsigned int free_count; + unsigned int free_max; + unsigned int free_lock; + // Other + ERS nodes; + DBComparator cmp; + DBHasher hash; + DBReleaser release; + DBNode ht[HASH_SIZE]; + DBNode cache; + DBType type; + DBOptions options; + uint32 item_count; + unsigned short maxlen; + unsigned global_lock : 1; } DBMap_impl; /** @@ -212,11 +212,11 @@ typedef struct DBMap_impl { * @see #DBNode */ typedef struct DBIterator_impl { - // Iterator interface - struct DBIterator vtable; - DBMap_impl* db; - int ht_index; - DBNode node; + // Iterator interface + struct DBIterator vtable; + DBMap_impl *db; + int ht_index; + DBNode node; } DBIterator_impl; #if defined(DB_ENABLE_STATS) @@ -227,92 +227,92 @@ typedef struct DBIterator_impl { * @see #stats */ static struct db_stats { - // Node alloc/free - uint32 db_node_alloc; - uint32 db_node_free; - // Database creating/destruction counters - uint32 db_int_alloc; - uint32 db_uint_alloc; - uint32 db_string_alloc; - uint32 db_istring_alloc; - uint32 db_int_destroy; - uint32 db_uint_destroy; - uint32 db_string_destroy; - uint32 db_istring_destroy; - // Function usage counters - uint32 db_rotate_left; - uint32 db_rotate_right; - uint32 db_rebalance; - uint32 db_rebalance_erase; - uint32 db_is_key_null; - uint32 db_dup_key; - uint32 db_dup_key_free; - uint32 db_free_add; - uint32 db_free_remove; - uint32 db_free_lock; - uint32 db_free_unlock; - uint32 db_int_cmp; - uint32 db_uint_cmp; - uint32 db_string_cmp; - uint32 db_istring_cmp; - uint32 db_int_hash; - uint32 db_uint_hash; - uint32 db_string_hash; - uint32 db_istring_hash; - uint32 db_release_nothing; - uint32 db_release_key; - uint32 db_release_data; - uint32 db_release_both; - uint32 dbit_first; - uint32 dbit_last; - uint32 dbit_next; - uint32 dbit_prev; - uint32 dbit_exists; - uint32 dbit_remove; - uint32 dbit_destroy; - uint32 db_iterator; - uint32 db_exists; - uint32 db_get; - uint32 db_getall; - uint32 db_vgetall; - uint32 db_ensure; - uint32 db_vensure; - uint32 db_put; - uint32 db_remove; - uint32 db_foreach; - uint32 db_vforeach; - uint32 db_clear; - uint32 db_vclear; - uint32 db_destroy; - uint32 db_vdestroy; - uint32 db_size; - uint32 db_type; - uint32 db_options; - uint32 db_fix_options; - uint32 db_default_cmp; - uint32 db_default_hash; - uint32 db_default_release; - uint32 db_custom_release; - uint32 db_alloc; - uint32 db_i2key; - uint32 db_ui2key; - uint32 db_str2key; - uint32 db_i2data; - uint32 db_ui2data; - uint32 db_ptr2data; - uint32 db_data2i; - uint32 db_data2ui; - uint32 db_data2ptr; - uint32 db_init; - uint32 db_final; + // Node alloc/free + uint32 db_node_alloc; + uint32 db_node_free; + // Database creating/destruction counters + uint32 db_int_alloc; + uint32 db_uint_alloc; + uint32 db_string_alloc; + uint32 db_istring_alloc; + uint32 db_int_destroy; + uint32 db_uint_destroy; + uint32 db_string_destroy; + uint32 db_istring_destroy; + // Function usage counters + uint32 db_rotate_left; + uint32 db_rotate_right; + uint32 db_rebalance; + uint32 db_rebalance_erase; + uint32 db_is_key_null; + uint32 db_dup_key; + uint32 db_dup_key_free; + uint32 db_free_add; + uint32 db_free_remove; + uint32 db_free_lock; + uint32 db_free_unlock; + uint32 db_int_cmp; + uint32 db_uint_cmp; + uint32 db_string_cmp; + uint32 db_istring_cmp; + uint32 db_int_hash; + uint32 db_uint_hash; + uint32 db_string_hash; + uint32 db_istring_hash; + uint32 db_release_nothing; + uint32 db_release_key; + uint32 db_release_data; + uint32 db_release_both; + uint32 dbit_first; + uint32 dbit_last; + uint32 dbit_next; + uint32 dbit_prev; + uint32 dbit_exists; + uint32 dbit_remove; + uint32 dbit_destroy; + uint32 db_iterator; + uint32 db_exists; + uint32 db_get; + uint32 db_getall; + uint32 db_vgetall; + uint32 db_ensure; + uint32 db_vensure; + uint32 db_put; + uint32 db_remove; + uint32 db_foreach; + uint32 db_vforeach; + uint32 db_clear; + uint32 db_vclear; + uint32 db_destroy; + uint32 db_vdestroy; + uint32 db_size; + uint32 db_type; + uint32 db_options; + uint32 db_fix_options; + uint32 db_default_cmp; + uint32 db_default_hash; + uint32 db_default_release; + uint32 db_custom_release; + uint32 db_alloc; + uint32 db_i2key; + uint32 db_ui2key; + uint32 db_str2key; + uint32 db_i2data; + uint32 db_ui2data; + uint32 db_ptr2data; + uint32 db_data2i; + uint32 db_data2ui; + uint32 db_data2ptr; + uint32 db_init; + uint32 db_final; } stats = { - 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, 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, 0, 0, 0, 0 }; #define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token #else /* !defined(DB_ENABLE_STATS) */ @@ -346,25 +346,25 @@ static struct db_stats { */ static void db_rotate_left(DBNode node, DBNode *root) { - DBNode y = node->right; + DBNode y = node->right; - DB_COUNTSTAT(db_rotate_left); - // put the left of y at the right of node - node->right = y->left; - if (y->left) - y->left->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->left) { - node->parent->left = y; // node was at the left - } else { - node->parent->right = y; // node was at the right - } - // put node at the left of y - y->left = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_left); + // put the left of y at the right of node + node->right = y->left; + if (y->left) + y->left->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->left) { + node->parent->left = y; // node was at the left + } else { + node->parent->right = y; // node was at the right + } + // put node at the left of y + y->left = node; + node->parent = y; } /** @@ -377,25 +377,25 @@ static void db_rotate_left(DBNode node, DBNode *root) */ static void db_rotate_right(DBNode node, DBNode *root) { - DBNode y = node->left; + DBNode y = node->left; - DB_COUNTSTAT(db_rotate_right); - // put the right of y at the left of node - node->left = y->right; - if (y->right != 0) - y->right->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->right) { - node->parent->right = y; // node was at the right - } else { - node->parent->left = y; // node was at the left - } - // put node at the right of y - y->right = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_right); + // put the right of y at the left of node + node->left = y->right; + if (y->right != 0) + y->right->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->right) { + node->parent->right = y; // node was at the right + } else { + node->parent->left = y; // node was at the left + } + // put node at the right of y + y->right = node; + node->parent = y; } /** @@ -410,55 +410,55 @@ static void db_rotate_right(DBNode node, DBNode *root) */ static void db_rebalance(DBNode node, DBNode *root) { - DBNode y; - - DB_COUNTSTAT(db_rebalance); - // Restore the RED-BLACK properties - node->color = RED; - while (node != *root && node->parent->color == RED) { - if (node->parent == node->parent->parent->left) { - // If node's parent is a left, y is node's right 'uncle' - y = node->parent->parent->right; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->right) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_left(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_right(node->parent->parent, root); - } - } else { - // If node's parent is a right, y is node's left 'uncle' - y = node->parent->parent->left; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->left) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_right(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_left(node->parent->parent, root); - } - } - } - (*root)->color = BLACK; // the root can and should always be black + DBNode y; + + DB_COUNTSTAT(db_rebalance); + // Restore the RED-BLACK properties + node->color = RED; + while (node != *root && node->parent->color == RED) { + if (node->parent == node->parent->parent->left) { + // If node's parent is a left, y is node's right 'uncle' + y = node->parent->parent->right; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->right) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_left(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_right(node->parent->parent, root); + } + } else { + // If node's parent is a right, y is node's left 'uncle' + y = node->parent->parent->left; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->left) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_right(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_left(node->parent->parent, root); + } + } + } + (*root)->color = BLACK; // the root can and should always be black } /** @@ -472,133 +472,133 @@ static void db_rebalance(DBNode node, DBNode *root) */ static void db_rebalance_erase(DBNode node, DBNode *root) { - DBNode y = node; - DBNode x = NULL; - DBNode x_parent = NULL; - DBNode w; - - DB_COUNTSTAT(db_rebalance_erase); - // Select where to change the tree - if (y->left == NULL) { // no left - x = y->right; - } else if (y->right == NULL) { // no right - x = y->left; - } else { // both exist, go to the leftmost node of the right sub-tree - y = y->right; - while (y->left != NULL) - y = y->left; - x = y->right; - } - - // Remove the node from the tree - if (y != node) { // both childs existed - // put the left of 'node' in the left of 'y' - node->left->parent = y; - y->left = node->left; - - // 'y' is not the direct child of 'node' - if (y != node->right) { - // put 'x' in the old position of 'y' - x_parent = y->parent; - if (x) x->parent = y->parent; - y->parent->left = x; - // put the right of 'node' in 'y' - y->right = node->right; - node->right->parent = y; - // 'y' is a direct child of 'node' - } else { - x_parent = y; - } - - // link 'y' and the parent of 'node' - if (*root == node) { - *root = y; // 'node' was the root - } else if (node->parent->left == node) { - node->parent->left = y; // 'node' was at the left - } else { - node->parent->right = y; // 'node' was at the right - } - y->parent = node->parent; - // switch colors - { - node_color tmp = y->color; - y->color = node->color; - node->color = tmp; - } - y = node; - } else { // one child did not exist - // put x in node's position - x_parent = y->parent; - if (x) x->parent = y->parent; - // link x and node's parent - if (*root == node) { - *root = x; // node was the root - } else if (node->parent->left == node) { - node->parent->left = x; // node was at the left - } else { - node->parent->right = x; // node was at the right - } - } - - // Restore the RED-BLACK properties - if (y->color != RED) { - while (x != *root && (x == NULL || x->color == BLACK)) { - if (x == x_parent->left) { - w = x_parent->right; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_left(x_parent, root); - w = x_parent->right; - } - if ((w->left == NULL || w->left->color == BLACK) && - (w->right == NULL || w->right->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->right == NULL || w->right->color == BLACK) { - if (w->left) w->left->color = BLACK; - w->color = RED; - db_rotate_right(w, root); - w = x_parent->right; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->right) w->right->color = BLACK; - db_rotate_left(x_parent, root); - break; - } - } else { - w = x_parent->left; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_right(x_parent, root); - w = x_parent->left; - } - if ((w->right == NULL || w->right->color == BLACK) && - (w->left == NULL || w->left->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->left == NULL || w->left->color == BLACK) { - if (w->right) w->right->color = BLACK; - w->color = RED; - db_rotate_left(w, root); - w = x_parent->left; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->left) w->left->color = BLACK; - db_rotate_right(x_parent, root); - break; - } - } - } - if (x) x->color = BLACK; - } + DBNode y = node; + DBNode x = NULL; + DBNode x_parent = NULL; + DBNode w; + + DB_COUNTSTAT(db_rebalance_erase); + // Select where to change the tree + if (y->left == NULL) { // no left + x = y->right; + } else if (y->right == NULL) { // no right + x = y->left; + } else { // both exist, go to the leftmost node of the right sub-tree + y = y->right; + while (y->left != NULL) + y = y->left; + x = y->right; + } + + // Remove the node from the tree + if (y != node) { // both childs existed + // put the left of 'node' in the left of 'y' + node->left->parent = y; + y->left = node->left; + + // 'y' is not the direct child of 'node' + if (y != node->right) { + // put 'x' in the old position of 'y' + x_parent = y->parent; + if (x) x->parent = y->parent; + y->parent->left = x; + // put the right of 'node' in 'y' + y->right = node->right; + node->right->parent = y; + // 'y' is a direct child of 'node' + } else { + x_parent = y; + } + + // link 'y' and the parent of 'node' + if (*root == node) { + *root = y; // 'node' was the root + } else if (node->parent->left == node) { + node->parent->left = y; // 'node' was at the left + } else { + node->parent->right = y; // 'node' was at the right + } + y->parent = node->parent; + // switch colors + { + node_color tmp = y->color; + y->color = node->color; + node->color = tmp; + } + y = node; + } else { // one child did not exist + // put x in node's position + x_parent = y->parent; + if (x) x->parent = y->parent; + // link x and node's parent + if (*root == node) { + *root = x; // node was the root + } else if (node->parent->left == node) { + node->parent->left = x; // node was at the left + } else { + node->parent->right = x; // node was at the right + } + } + + // Restore the RED-BLACK properties + if (y->color != RED) { + while (x != *root && (x == NULL || x->color == BLACK)) { + if (x == x_parent->left) { + w = x_parent->right; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left(x_parent, root); + w = x_parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && + (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left) w->left->color = BLACK; + w->color = RED; + db_rotate_right(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) w->right->color = BLACK; + db_rotate_left(x_parent, root); + break; + } + } else { + w = x_parent->left; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right(x_parent, root); + w = x_parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && + (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right) w->right->color = BLACK; + w->color = RED; + db_rotate_left(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) w->left->color = BLACK; + db_rotate_right(x_parent, root); + break; + } + } + } + if (x) x->color = BLACK; + } } /** @@ -613,15 +613,15 @@ static void db_rebalance_erase(DBNode node, DBNode *root) */ static int db_is_key_null(DBType type, DBKey key) { - DB_COUNTSTAT(db_is_key_null); - switch (type) { - case DB_STRING: - case DB_ISTRING: - return (key.str == NULL); + DB_COUNTSTAT(db_is_key_null); + switch (type) { + case DB_STRING: + case DB_ISTRING: + return (key.str == NULL); - default: // Not a pointer - return 0; - } + default: // Not a pointer + return 0; + } } /** @@ -635,25 +635,25 @@ static int db_is_key_null(DBType type, DBKey key) * @see #db_obj_put(DBMap*,DBKey,void *) * @see #db_dup_key_free(DBMap_impl*,DBKey) */ -static DBKey db_dup_key(DBMap_impl* db, DBKey key) +static DBKey db_dup_key(DBMap_impl *db, DBKey key) { - char *str; - size_t len; + char *str; + size_t len; - DB_COUNTSTAT(db_dup_key); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - len = strnlen(key.str, db->maxlen); - str = (char*)aMalloc(len + 1); - memcpy(str, key.str, len); - str[len] = '\0'; - key.str = str; - return key; + DB_COUNTSTAT(db_dup_key); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + len = strnlen(key.str, db->maxlen); + str = (char *)aMalloc(len + 1); + memcpy(str, key.str, len); + str[len] = '\0'; + key.str = str; + return key; - default: - return key; - } + default: + return key; + } } /** @@ -663,18 +663,18 @@ static DBKey db_dup_key(DBMap_impl* db, DBKey key) * @private * @see #db_dup_key(DBMap_impl*,DBKey) */ -static void db_dup_key_free(DBMap_impl* db, DBKey key) +static void db_dup_key_free(DBMap_impl *db, DBKey key) { - DB_COUNTSTAT(db_dup_key_free); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - aFree((char*)key.str); - return; + DB_COUNTSTAT(db_dup_key_free); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + aFree((char *)key.str); + return; - default: - return; - } + default: + return; + } } /** @@ -692,40 +692,40 @@ static void db_dup_key_free(DBMap_impl* db, DBKey key) * @see #db_obj_remove(DBMap*,DBKey) * @see #db_free_remove(DBMap_impl*,DBNode) */ -static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) -{ - DBKey old_key; - - DB_COUNTSTAT(db_free_add); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_add: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed - old_key = node->key; - node->key = db_dup_key(db, node->key); - db->release(old_key, node->data, DB_RELEASE_KEY); - } - if (db->free_count == db->free_max) { // No more space, expand free_list - db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 - if (db->free_max <= db->free_count) { - if (db->free_count == (unsigned int)~0) { - ShowFatalError("db_free_add: free_count overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_max = (unsigned int)~0; - } - RECREATE(db->free_list, struct db_free, db->free_max); - } - node->deleted = 1; - db->free_list[db->free_count].node = node; - db->free_list[db->free_count].root = root; - db->free_count++; - db->item_count--; +static void db_free_add(DBMap_impl *db, DBNode node, DBNode *root) +{ + DBKey old_key; + + DB_COUNTSTAT(db_free_add); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_add: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed + old_key = node->key; + node->key = db_dup_key(db, node->key); + db->release(old_key, node->data, DB_RELEASE_KEY); + } + if (db->free_count == db->free_max) { // No more space, expand free_list + db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 + if (db->free_max <= db->free_count) { + if (db->free_count == (unsigned int)~0) { + ShowFatalError("db_free_add: free_count overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_max = (unsigned int)~0; + } + RECREATE(db->free_list, struct db_free, db->free_max); + } + node->deleted = 1; + db->free_list[db->free_count].node = node; + db->free_list[db->free_count].root = root; + db->free_count++; + db->item_count--; } /** @@ -741,26 +741,26 @@ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) * @see #db_obj_put(DBMap*,DBKey,DBData) * @see #db_free_add(DBMap_impl*,DBNode*,DBNode) */ -static void db_free_remove(DBMap_impl* db, DBNode node) +static void db_free_remove(DBMap_impl *db, DBNode node) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_remove); - for (i = 0; i < db->free_count; i++) { - if (db->free_list[i].node == node) { - if (i < db->free_count -1) // copy the last item to where the removed one was - memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); - db_dup_key_free(db, node->key); - break; - } - } - node->deleted = 0; - if (i == db->free_count) { - ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); - } else { - db->free_count--; - } - db->item_count++; + DB_COUNTSTAT(db_free_remove); + for (i = 0; i < db->free_count; i++) { + if (db->free_list[i].node == node) { + if (i < db->free_count -1) // copy the last item to where the removed one was + memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); + db_dup_key_free(db, node->key); + break; + } + } + node->deleted = 0; + if (i == db->free_count) { + ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); + } else { + db->free_count--; + } + db->item_count++; } /** @@ -770,16 +770,16 @@ static void db_free_remove(DBMap_impl* db, DBNode node) * @see DBMap_impl#free_lock * @see #db_unlock(DBMap_impl*) */ -static void db_free_lock(DBMap_impl* db) +static void db_free_lock(DBMap_impl *db) { - DB_COUNTSTAT(db_free_lock); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_lock: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_lock++; + DB_COUNTSTAT(db_free_lock); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_lock: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_lock++; } /** @@ -793,28 +793,28 @@ static void db_free_lock(DBMap_impl* db) * @see #db_free_dbn(DBNode) * @see #db_lock(DBMap_impl*) */ -static void db_free_unlock(DBMap_impl* db) +static void db_free_unlock(DBMap_impl *db) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_unlock); - if (db->free_lock == 0) { - ShowWarning("db_free_unlock: free_lock was already 0\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - } else { - db->free_lock--; - } - if (db->free_lock) - return; // Not last lock + DB_COUNTSTAT(db_free_unlock); + if (db->free_lock == 0) { + ShowWarning("db_free_unlock: free_lock was already 0\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + } else { + db->free_lock--; + } + if (db->free_lock) + return; // Not last lock - for (i = 0; i < db->free_count ; i++) { - db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); - db_dup_key_free(db, db->free_list[i].node->key); - DB_COUNTSTAT(db_node_free); - ers_free(db->nodes, db->free_list[i].node); - } - db->free_count = 0; + for (i = 0; i < db->free_count ; i++) { + db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); + db_dup_key_free(db, db->free_list[i].node->key); + DB_COUNTSTAT(db_node_free); + ers_free(db->nodes, db->free_list[i].node); + } + db->free_count = 0; } /*****************************************************************************\ @@ -850,11 +850,11 @@ static void db_free_unlock(DBMap_impl* db) */ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_cmp); - if (key1.i < key2.i) return -1; - if (key1.i > key2.i) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_cmp); + if (key1.i < key2.i) return -1; + if (key1.i > key2.i) return 1; + return 0; } /** @@ -872,11 +872,11 @@ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_cmp); - if (key1.ui < key2.ui) return -1; - if (key1.ui > key2.ui) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_cmp); + if (key1.ui < key2.ui) return -1; + if (key1.ui > key2.ui) return 1; + return 0; } /** @@ -893,8 +893,8 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_string_cmp); - return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_string_cmp); + return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -911,8 +911,8 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_istring_cmp); - return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_istring_cmp); + return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -928,9 +928,9 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_hash); - return (unsigned int)key.i; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_hash); + return (unsigned int)key.i; } /** @@ -946,9 +946,9 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_hash); - return key.ui; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_hash); + return key.ui; } /** @@ -962,20 +962,20 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_string_hash); + DB_COUNTSTAT(db_string_hash); - for (i = 0; *k; ++i) { - hash = (hash*33 + ((unsigned char)*k))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; ++i) { + hash = (hash*33 + ((unsigned char)*k))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -988,20 +988,20 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_istring_hash); + DB_COUNTSTAT(db_istring_hash); - for (i = 0; *k; i++) { - hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; i++) { + hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -1015,8 +1015,10 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) */ static void db_release_nothing(DBKey key, DBData data, DBRelease which) { - (void)key;(void)data;(void)which;//not used - DB_COUNTSTAT(db_release_nothing); + (void)key; + (void)data; + (void)which;//not used + DB_COUNTSTAT(db_release_nothing); } /** @@ -1030,9 +1032,9 @@ static void db_release_nothing(DBKey key, DBData data, DBRelease which) */ static void db_release_key(DBKey key, DBData data, DBRelease which) { - (void)data;//not used - DB_COUNTSTAT(db_release_key); - if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer + (void)data;//not used + DB_COUNTSTAT(db_release_key); + if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer } /** @@ -1048,9 +1050,9 @@ static void db_release_key(DBKey key, DBData data, DBRelease which) */ static void db_release_data(DBKey key, DBData data, DBRelease which) { - (void)key;//not used - DB_COUNTSTAT(db_release_data); - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + (void)key;//not used + DB_COUNTSTAT(db_release_data); + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /** @@ -1067,9 +1069,9 @@ static void db_release_data(DBKey key, DBData data, DBRelease which) */ static void db_release_both(DBKey key, DBData data, DBRelease which) { - DB_COUNTSTAT(db_release_both); - if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + DB_COUNTSTAT(db_release_both); + if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /*****************************************************************************\ @@ -1115,16 +1117,16 @@ static void db_release_both(DBKey key, DBData data, DBRelease which) * @protected * @see DBIterator#first */ -DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) +DBData *dbit_obj_first(DBIterator *self, DBKey *out_key) { - DBIterator_impl* it = (DBIterator_impl*)self; - - DB_COUNTSTAT(dbit_first); - // position before the first entry - it->ht_index = -1; - it->node = NULL; - // get next entry - return self->next(self, out_key); + DBIterator_impl *it = (DBIterator_impl *)self; + + DB_COUNTSTAT(dbit_first); + // position before the first entry + it->ht_index = -1; + it->node = NULL; + // get next entry + return self->next(self, out_key); } /** @@ -1137,16 +1139,16 @@ DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#last */ -DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) +DBData *dbit_obj_last(DBIterator *self, DBKey *out_key) { - DBIterator_impl* it = (DBIterator_impl*)self; - - DB_COUNTSTAT(dbit_last); - // position after the last entry - it->ht_index = HASH_SIZE; - it->node = NULL; - // get previous entry - return self->prev(self, out_key); + DBIterator_impl *it = (DBIterator_impl *)self; + + DB_COUNTSTAT(dbit_last); + // position after the last entry + it->ht_index = HASH_SIZE; + it->node = NULL; + // get previous entry + return self->prev(self, out_key); } /** @@ -1159,70 +1161,67 @@ DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#next */ -DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) -{ - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_next); - if( it->ht_index < 0 ) - {// get first node - it->ht_index = 0; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for( ; it->ht_index < HASH_SIZE; ++(it->ht_index) ) - { - // Iterate in the order: left tree, current node, right tree - if( node == NULL ) - {// prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if( node == NULL ) - continue;// next hash - fake.right = node; - node = &fake; - } - - while( node ) - {// next node - if( node->right ) - {// continue in the right subtree - node = node->right; - while( node->left ) - node = node->left;// get leftmost node - } - else - {// continue to the next parent (recursive) - parent = node->parent; - while( parent ) - { - if( parent->right != node ) - break; - node = parent; - parent = node->parent; - } - if( parent == NULL ) - {// next hash - node = NULL; - break; - } - node = parent; - } - - if( !node->deleted ) - {// found next entry - it->node = node; - if( out_key ) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData *dbit_obj_next(DBIterator *self, DBKey *out_key) +{ + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_next); + if (it->ht_index < 0) { + // get first node + it->ht_index = 0; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for (; it->ht_index < HASH_SIZE; ++(it->ht_index)) { + // Iterate in the order: left tree, current node, right tree + if (node == NULL) { + // prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if (node == NULL) + continue;// next hash + fake.right = node; + node = &fake; + } + + while (node) { + // next node + if (node->right) { + // continue in the right subtree + node = node->right; + while (node->left) + node = node->left;// get leftmost node + } else { + // continue to the next parent (recursive) + parent = node->parent; + while (parent) { + if (parent->right != node) + break; + node = parent; + parent = node->parent; + } + if (parent == NULL) { + // next hash + node = NULL; + break; + } + node = parent; + } + + if (!node->deleted) { + // found next entry + it->node = node; + if (out_key) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** @@ -1235,93 +1234,90 @@ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#prev */ -DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) -{ - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_prev); - if( it->ht_index >= HASH_SIZE ) - {// get last node - it->ht_index = HASH_SIZE-1; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for( ; it->ht_index >= 0; --(it->ht_index) ) - { - // Iterate in the order: right tree, current node, left tree - if( node == NULL ) - {// prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if( node == NULL ) - continue;// next hash - fake.left = node; - node = &fake; - } - - - while( node ) - {// next node - if( node->left ) - {// continue in the left subtree - node = node->left; - while( node->right ) - node = node->right;// get rightmost node - } - else - {// continue to the next parent (recursive) - parent = node->parent; - while( parent ) - { - if( parent->left != node ) - break; - node = parent; - parent = node->parent; - } - if( parent == NULL ) - {// next hash - node = NULL; - break; - } - node = parent; - } - - if( !node->deleted ) - {// found previous entry - it->node = node; - if( out_key ) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData *dbit_obj_prev(DBIterator *self, DBKey *out_key) +{ + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_prev); + if (it->ht_index >= HASH_SIZE) { + // get last node + it->ht_index = HASH_SIZE-1; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for (; it->ht_index >= 0; --(it->ht_index)) { + // Iterate in the order: right tree, current node, left tree + if (node == NULL) { + // prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if (node == NULL) + continue;// next hash + fake.left = node; + node = &fake; + } + + + while (node) { + // next node + if (node->left) { + // continue in the left subtree + node = node->left; + while (node->right) + node = node->right;// get rightmost node + } else { + // continue to the next parent (recursive) + parent = node->parent; + while (parent) { + if (parent->left != node) + break; + node = parent; + parent = node->parent; + } + if (parent == NULL) { + // next hash + node = NULL; + break; + } + node = parent; + } + + if (!node->deleted) { + // found previous entry + it->node = node; + if (out_key) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if + * The databases entries might have NULL data, so use this to to test if * the iterator is done. * @param self Iterator * @return true if the entry exists * @protected * @see DBIterator#exists */ -bool dbit_obj_exists(DBIterator* self) +bool dbit_obj_exists(DBIterator *self) { - DBIterator_impl* it = (DBIterator_impl*)self; + DBIterator_impl *it = (DBIterator_impl *)self; - DB_COUNTSTAT(dbit_exists); - return (it->node && !it->node->deleted); + DB_COUNTSTAT(dbit_exists); + return (it->node && !it->node->deleted); } /** * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry + * NOTE: {@link DBIterator#exists} will return false until another entry * is fetched * Puts data of the removed entry in out_data, if out_data is not NULL. * @param self Iterator @@ -1331,26 +1327,25 @@ bool dbit_obj_exists(DBIterator* self) * @see DBMap#remove * @see DBIterator#remove */ -int dbit_obj_remove(DBIterator* self, DBData *out_data) +int dbit_obj_remove(DBIterator *self, DBData *out_data) { - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - int retval = 0; + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + int retval = 0; - DB_COUNTSTAT(dbit_remove); - node = it->node; - if( node && !node->deleted ) - { - DBMap_impl* db = it->db; - if( db->cache == node ) - db->cache = NULL; - if( out_data ) - memcpy(out_data, &node->data, sizeof(DBData)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[it->ht_index]); - } - return retval; + DB_COUNTSTAT(dbit_remove); + node = it->node; + if (node && !node->deleted) { + DBMap_impl *db = it->db; + if (db->cache == node) + db->cache = NULL; + if (out_data) + memcpy(out_data, &node->data, sizeof(DBData)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[it->ht_index]); + } + return retval; } /** @@ -1358,48 +1353,48 @@ int dbit_obj_remove(DBIterator* self, DBData *out_data) * @param self Iterator * @protected */ -void dbit_obj_destroy(DBIterator* self) +void dbit_obj_destroy(DBIterator *self) { - DBIterator_impl* it = (DBIterator_impl*)self; + DBIterator_impl *it = (DBIterator_impl *)self; - DB_COUNTSTAT(dbit_destroy); - // unlock the database - db_free_unlock(it->db); - // free iterator - aFree(self); + DB_COUNTSTAT(dbit_destroy); + // unlock the database + db_free_unlock(it->db); + // free iterator + aFree(self); } /** * Returns a new iterator for this database. * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal + * The database will keep functioning normally but will only free internal * memory when unlocked, so destroy the iterator as soon as possible. * @param self Database * @return New iterator * @protected */ -static DBIterator* db_obj_iterator(DBMap* self) +static DBIterator *db_obj_iterator(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBIterator_impl* it; + DBMap_impl *db = (DBMap_impl *)self; + DBIterator_impl *it; - DB_COUNTSTAT(db_iterator); - CREATE(it, struct DBIterator_impl, 1); - /* Interface of the iterator **/ - it->vtable.first = dbit_obj_first; - it->vtable.last = dbit_obj_last; - it->vtable.next = dbit_obj_next; - it->vtable.prev = dbit_obj_prev; - it->vtable.exists = dbit_obj_exists; - it->vtable.remove = dbit_obj_remove; - it->vtable.destroy = dbit_obj_destroy; - /* Initial state (before the first entry) */ - it->db = db; - it->ht_index = -1; - it->node = NULL; - /* Lock the database */ - db_free_lock(db); - return &it->vtable; + DB_COUNTSTAT(db_iterator); + CREATE(it, struct DBIterator_impl, 1); + /* Interface of the iterator **/ + it->vtable.first = dbit_obj_first; + it->vtable.last = dbit_obj_last; + it->vtable.next = dbit_obj_next; + it->vtable.prev = dbit_obj_prev; + it->vtable.exists = dbit_obj_exists; + it->vtable.remove = dbit_obj_remove; + it->vtable.destroy = dbit_obj_destroy; + /* Initial state (before the first entry) */ + it->db = db; + it->ht_index = -1; + it->node = NULL; + /* Lock the database */ + db_free_lock(db); + return &it->vtable; } /** @@ -1410,47 +1405,47 @@ static DBIterator* db_obj_iterator(DBMap* self) * @protected * @see DBMap#exists */ -static bool db_obj_exists(DBMap* self, DBKey key) +static bool db_obj_exists(DBMap *self, DBKey key) { - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - int c; - bool found = false; + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + int c; + bool found = false; - DB_COUNTSTAT(db_exists); - if (db == NULL) return false; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - return false; // nullpo candidate - } + DB_COUNTSTAT(db_exists); + if (db == NULL) return false; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + return false; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); - return false; - } + if (db->cache->deleted) { + ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); + return false; + } #endif - return true; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - db->cache = node; - found = true; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return found; + return true; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + db->cache = node; + found = true; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return found; } /** @@ -1461,48 +1456,48 @@ static bool db_obj_exists(DBMap* self, DBKey key) * @protected * @see DBMap#get */ -static DBData* db_obj_get(DBMap* self, DBKey key) +static DBData *db_obj_get(DBMap *self, DBKey key) { - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - int c; - DBData *data = NULL; + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + int c; + DBData *data = NULL; - DB_COUNTSTAT(db_get); - if (db == NULL) return NULL; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } + DB_COUNTSTAT(db_get); + if (db == NULL) return NULL; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); - return NULL; - } + if (db->cache->deleted) { + ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); + return NULL; + } #endif - return &db->cache->data; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - data = &node->data; - db->cache = node; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return data; + return &db->cache->data; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + data = &node->data; + db->cache = node; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return data; } /** @@ -1510,7 +1505,7 @@ static DBData* db_obj_get(DBMap* self, DBKey key) * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1521,58 +1516,58 @@ static DBData* db_obj_get(DBMap* self, DBKey key) * @protected * @see DBMap#vgetall */ -static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - unsigned int i; - DBNode node; - DBNode parent; - unsigned int ret = 0; - - DB_COUNTSTAT(db_vgetall); - if (db == NULL) return 0; // nullpo candidate - if (match == NULL) return 0; // nullpo candidate - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Match in the order: current node, left tree, right tree - node = db->ht[i]; - while (node) { - - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - if (match(node->key, node->data, argscopy) == 0) { - if (buf && ret < max) - buf[ret] = &node->data; - ret++; - } - va_end(argscopy); - } - - if (node->left) { - node = node->left; - continue; - } - - if (node->right) { - node = node->right; - continue; - } - - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - - } - } - db_free_unlock(db); - return ret; +static unsigned int db_obj_vgetall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + unsigned int i; + DBNode node; + DBNode parent; + unsigned int ret = 0; + + DB_COUNTSTAT(db_vgetall); + if (db == NULL) return 0; // nullpo candidate + if (match == NULL) return 0; // nullpo candidate + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Match in the order: current node, left tree, right tree + node = db->ht[i]; + while (node) { + + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + if (match(node->key, node->data, argscopy) == 0) { + if (buf && ret < max) + buf[ret] = &node->data; + ret++; + } + va_end(argscopy); + } + + if (node->left) { + node = node->left; + continue; + } + + if (node->right) { + node = node->right; + continue; + } + + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + + } + } + db_free_unlock(db); + return ret; } /** @@ -1581,7 +1576,7 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1593,23 +1588,23 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, * @see DBMap#vgetall * @see DBMap#getall */ -static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, ...) +static unsigned int db_obj_getall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...) { - va_list args; - unsigned int ret; + va_list args; + unsigned int ret; - DB_COUNTSTAT(db_getall); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_getall); + if (self == NULL) return 0; // nullpo candidate - va_start(args, match); - ret = self->vgetall(self, buf, max, match, args); - va_end(args); - return ret; + va_start(args, match); + ret = self->vgetall(self, buf, max, match, args); + va_end(args); + return ret; } /** * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1619,96 +1614,96 @@ static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, D * @protected * @see DBMap#vensure */ -static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - DBNode parent = NULL; - unsigned int hash; - int c = 0; - DBData *data = NULL; - - DB_COUNTSTAT(db_vensure); - if (db == NULL) return NULL; // nullpo candidate - if (create == NULL) { - ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) - return &db->cache->data; // cache hit - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - node = db->ht[hash]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - break; - } - parent = node; - if (c < 0) - node = node->left; - else - node = node->right; - } - // Create node if necessary - if (node == NULL) { - va_list argscopy; - if (db->item_count == UINT32_MAX) { - ShowError("db_vensure: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return NULL; - } - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, *data, DB_RELEASE_KEY); - } else { - node->key = key; - } - va_copy(argscopy, args); - node->data = create(key, argscopy); - va_end(argscopy); - } - data = &node->data; - db->cache = node; - db_free_unlock(db); - return data; +static DBData *db_obj_vensure(DBMap *self, DBKey key, DBCreateData create, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + DBNode parent = NULL; + unsigned int hash; + int c = 0; + DBData *data = NULL; + + DB_COUNTSTAT(db_vensure); + if (db == NULL) return NULL; // nullpo candidate + if (create == NULL) { + ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) + return &db->cache->data; // cache hit + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + node = db->ht[hash]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + break; + } + parent = node; + if (c < 0) + node = node->left; + else + node = node->right; + } + // Create node if necessary + if (node == NULL) { + va_list argscopy; + if (db->item_count == UINT32_MAX) { + ShowError("db_vensure: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return NULL; + } + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, *data, DB_RELEASE_KEY); + } else { + node->key = key; + } + va_copy(argscopy, args); + node->data = create(key, argscopy); + va_end(argscopy); + } + data = &node->data; + db->cache = node; + db_free_unlock(db); + return data; } /** * Just calls {@link DBMap#vensure}. * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1719,18 +1714,18 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li * @see DBMap#vensure * @see DBMap#ensure */ -static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) +static DBData *db_obj_ensure(DBMap *self, DBKey key, DBCreateData create, ...) { - va_list args; - DBData *ret = NULL; + va_list args; + DBData *ret = NULL; - DB_COUNTSTAT(db_ensure); - if (self == NULL) return NULL; // nullpo candidate + DB_COUNTSTAT(db_ensure); + if (self == NULL) return NULL; // nullpo candidate - va_start(args, create); - ret = self->vensure(self, key, create, args); - va_end(args); - return ret; + va_start(args, create); + ret = self->vensure(self, key, create, args); + va_end(args); + return ret; } /** @@ -1746,97 +1741,97 @@ static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) * @see #db_malloc_dbn(void) * @see DBMap#put */ -static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - DBNode parent = NULL; - int c = 0, retval = 0; - unsigned int hash; - - DB_COUNTSTAT(db_put); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { - ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - if (db->item_count == UINT32_MAX) { - ShowError("db_put: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return 0; - } - // search for an equal node - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for (node = db->ht[hash]; node; ) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { // equal entry, replace - if (node->deleted) { - db_free_remove(db, node); - } else { - db->release(node->key, node->data, DB_RELEASE_BOTH); - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - } - break; - } - parent = node; - if (c < 0) { - node = node->left; - } else { - node = node->right; - } - } - // allocate a new node if necessary - if (node == NULL) { - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, data, DB_RELEASE_KEY); - } else { - node->key = key; - } - node->data = data; - db->cache = node; - db_free_unlock(db); - return retval; +static int db_obj_put(DBMap *self, DBKey key, DBData data, DBData *out_data) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + DBNode parent = NULL; + int c = 0, retval = 0; + unsigned int hash; + + DB_COUNTSTAT(db_put); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { + ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + if (db->item_count == UINT32_MAX) { + ShowError("db_put: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return 0; + } + // search for an equal node + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for (node = db->ht[hash]; node;) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { // equal entry, replace + if (node->deleted) { + db_free_remove(db, node); + } else { + db->release(node->key, node->data, DB_RELEASE_BOTH); + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + } + break; + } + parent = node; + if (c < 0) { + node = node->left; + } else { + node = node->right; + } + } + // allocate a new node if necessary + if (node == NULL) { + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, data, DB_RELEASE_KEY); + } else { + node->key = key; + } + node->data = data; + db->cache = node; + db_free_unlock(db); + return retval; } /** @@ -1851,49 +1846,49 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) * @see #db_free_add(DBMap_impl*,DBNode,DBNode *) * @see DBMap#remove */ -static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - unsigned int hash; - int c = 0, retval = 0; - - DB_COUNTSTAT(db_remove); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for(node = db->ht[hash]; node; ){ - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - if (db->cache == node) - db->cache = NULL; - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[hash]); - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return retval; +static int db_obj_remove(DBMap *self, DBKey key, DBData *out_data) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + unsigned int hash; + int c = 0, retval = 0; + + DB_COUNTSTAT(db_remove); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for (node = db->ht[hash]; node;) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + if (db->cache == node) + db->cache = NULL; + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[hash]); + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return retval; } /** @@ -1906,52 +1901,52 @@ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) * @protected * @see DBMap#vforeach */ -static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - unsigned int i; - int sum = 0; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vforeach); - if (db == NULL) return 0; // nullpo candidate - if (func == NULL) { - ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Apply func in the order: current node, left node, right node - node = db->ht[i]; - while (node) { - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - } - } - db_free_unlock(db); - return sum; +static int db_obj_vforeach(DBMap *self, DBApply func, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + unsigned int i; + int sum = 0; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vforeach); + if (db == NULL) return 0; // nullpo candidate + if (func == NULL) { + ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Apply func in the order: current node, left node, right node + node = db->ht[i]; + while (node) { + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + } + } + db_free_unlock(db); + return sum; } /** @@ -1966,18 +1961,18 @@ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) * @see DBMap#vforeach * @see DBMap#foreach */ -static int db_obj_foreach(DBMap* self, DBApply func, ...) +static int db_obj_foreach(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_foreach); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_foreach); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vforeach(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vforeach(self, func, args); + va_end(args); + return ret; } /** @@ -1992,62 +1987,61 @@ static int db_obj_foreach(DBMap* self, DBApply func, ...) * @protected * @see DBMap#vclear */ -static int db_obj_vclear(DBMap* self, DBApply func, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - int sum = 0; - unsigned int i; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vclear); - if (db == NULL) return 0; // nullpo candidate - - db_free_lock(db); - db->cache = NULL; - for (i = 0; i < HASH_SIZE; i++) { - // Apply the func and delete in the order: left tree, right tree, current node - node = db->ht[i]; - db->ht[i] = NULL; - while (node) { - parent = node->parent; - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - if (node->deleted) { - db_dup_key_free(db, node->key); - } else { - if (func) - { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - db->release(node->key, node->data, DB_RELEASE_BOTH); - node->deleted = 1; - } - DB_COUNTSTAT(db_node_free); - if (parent) { - if (parent->left == node) - parent->left = NULL; - else - parent->right = NULL; - } - ers_free(db->nodes, node); - node = parent; - } - db->ht[i] = NULL; - } - db->free_count = 0; - db->item_count = 0; - db_free_unlock(db); - return sum; +static int db_obj_vclear(DBMap *self, DBApply func, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + int sum = 0; + unsigned int i; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vclear); + if (db == NULL) return 0; // nullpo candidate + + db_free_lock(db); + db->cache = NULL; + for (i = 0; i < HASH_SIZE; i++) { + // Apply the func and delete in the order: left tree, right tree, current node + node = db->ht[i]; + db->ht[i] = NULL; + while (node) { + parent = node->parent; + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + if (node->deleted) { + db_dup_key_free(db, node->key); + } else { + if (func) { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + db->release(node->key, node->data, DB_RELEASE_BOTH); + node->deleted = 1; + } + DB_COUNTSTAT(db_node_free); + if (parent) { + if (parent->left == node) + parent->left = NULL; + else + parent->right = NULL; + } + ers_free(db->nodes, node); + node = parent; + } + db->ht[i] = NULL; + } + db->free_count = 0; + db->item_count = 0; + db_free_unlock(db); + return sum; } /** @@ -2056,7 +2050,7 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2066,25 +2060,25 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) * @see DBMap#vclear * @see DBMap#clear */ -static int db_obj_clear(DBMap* self, DBApply func, ...) +static int db_obj_clear(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_clear); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_clear); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vclear(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vclear(self, func, args); + va_end(args); + return ret; } /** * Finalize the database, feeing all the memory it uses. * Before deleting an entry, func is applied to it. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2093,42 +2087,50 @@ static int db_obj_clear(DBMap* self, DBApply func, ...) * @protected * @see DBMap#vdestroy */ -static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) +static int db_obj_vdestroy(DBMap *self, DBApply func, va_list args) { - DBMap_impl* db = (DBMap_impl*)self; - int sum; + DBMap_impl *db = (DBMap_impl *)self; + int sum; - DB_COUNTSTAT(db_vdestroy); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; - } - if (db->free_lock) - ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" - "Database allocated at %s:%d\n", - db->free_lock, db->alloc_file, db->alloc_line); + DB_COUNTSTAT(db_vdestroy); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; + } + if (db->free_lock) + ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" + "Database allocated at %s:%d\n", + db->free_lock, db->alloc_file, db->alloc_line); #ifdef DB_ENABLE_STATS - switch (db->type) { - case DB_INT: DB_COUNTSTAT(db_int_destroy); break; - case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break; - case DB_STRING: DB_COUNTSTAT(db_string_destroy); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break; - } + switch (db->type) { + case DB_INT: + DB_COUNTSTAT(db_int_destroy); + break; + case DB_UINT: + DB_COUNTSTAT(db_uint_destroy); + break; + case DB_STRING: + DB_COUNTSTAT(db_string_destroy); + break; + case DB_ISTRING: + DB_COUNTSTAT(db_istring_destroy); + break; + } #endif /* DB_ENABLE_STATS */ - db_free_lock(db); - db->global_lock = 1; - sum = self->vclear(self, func, args); - aFree(db->free_list); - db->free_list = NULL; - db->free_max = 0; - ers_destroy(db->nodes); - db_free_unlock(db); - aFree(db); - return sum; + db_free_lock(db); + db->global_lock = 1; + sum = self->vclear(self, func, args); + aFree(db->free_list); + db->free_list = NULL; + db->free_max = 0; + ers_destroy(db->nodes); + db_free_unlock(db); + aFree(db); + return sum; } /** @@ -2137,7 +2139,7 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted. * @param self Database * @param func Function to be applied to every entry before deleting @@ -2147,18 +2149,18 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) * @see DBMap#vdestroy * @see DBMap#destroy */ -static int db_obj_destroy(DBMap* self, DBApply func, ...) +static int db_obj_destroy(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_destroy); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_destroy); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vdestroy(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vdestroy(self, func, args); + va_end(args); + return ret; } /** @@ -2169,19 +2171,19 @@ static int db_obj_destroy(DBMap* self, DBApply func, ...) * @see DBMap_impl#item_count * @see DBMap#size */ -static unsigned int db_obj_size(DBMap* self) +static unsigned int db_obj_size(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - unsigned int item_count; + DBMap_impl *db = (DBMap_impl *)self; + unsigned int item_count; - DB_COUNTSTAT(db_size); - if (db == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_size); + if (db == NULL) return 0; // nullpo candidate - db_free_lock(db); - item_count = db->item_count; - db_free_unlock(db); + db_free_lock(db); + item_count = db->item_count; + db_free_unlock(db); - return item_count; + return item_count; } /** @@ -2192,19 +2194,19 @@ static unsigned int db_obj_size(DBMap* self) * @see DBMap_impl#type * @see DBMap#type */ -static DBType db_obj_type(DBMap* self) +static DBType db_obj_type(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBType type; + DBMap_impl *db = (DBMap_impl *)self; + DBType type; - DB_COUNTSTAT(db_type); - if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_type); + if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? - db_free_lock(db); - type = db->type; - db_free_unlock(db); + db_free_lock(db); + type = db->type; + db_free_unlock(db); - return type; + return type; } /** @@ -2215,19 +2217,19 @@ static DBType db_obj_type(DBMap* self) * @see DBMap_impl#options * @see DBMap#options */ -static DBOptions db_obj_options(DBMap* self) +static DBOptions db_obj_options(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBOptions options; + DBMap_impl *db = (DBMap_impl *)self; + DBOptions options; - DB_COUNTSTAT(db_options); - if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_options); + if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? - db_free_lock(db); - options = db->options; - db_free_unlock(db); + db_free_lock(db); + options = db->options; + db_free_unlock(db); - return options; + return options; } /*****************************************************************************\ @@ -2264,18 +2266,18 @@ static DBOptions db_obj_options(DBMap* self) */ DBOptions db_fix_options(DBType type, DBOptions options) { - DB_COUNTSTAT(db_fix_options); - switch (type) { - case DB_INT: - case DB_UINT: // Numeric database, do nothing with the keys - return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); + DB_COUNTSTAT(db_fix_options); + switch (type) { + case DB_INT: + case DB_UINT: // Numeric database, do nothing with the keys + return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); - default: - ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); - case DB_STRING: - case DB_ISTRING: // String databases, no fix required - return options; - } + default: + ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); + case DB_STRING: + case DB_ISTRING: // String databases, no fix required + return options; + } } /** @@ -2290,16 +2292,20 @@ DBOptions db_fix_options(DBType type, DBOptions options) */ DBComparator db_default_cmp(DBType type) { - DB_COUNTSTAT(db_default_cmp); - switch (type) { - case DB_INT: return &db_int_cmp; - case DB_UINT: return &db_uint_cmp; - case DB_STRING: return &db_string_cmp; - case DB_ISTRING: return &db_istring_cmp; - default: - ShowError("db_default_cmp: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_cmp); + switch (type) { + case DB_INT: + return &db_int_cmp; + case DB_UINT: + return &db_uint_cmp; + case DB_STRING: + return &db_string_cmp; + case DB_ISTRING: + return &db_istring_cmp; + default: + ShowError("db_default_cmp: Unknown database type %u\n", type); + return NULL; + } } /** @@ -2314,20 +2320,24 @@ DBComparator db_default_cmp(DBType type) */ DBHasher db_default_hash(DBType type) { - DB_COUNTSTAT(db_default_hash); - switch (type) { - case DB_INT: return &db_int_hash; - case DB_UINT: return &db_uint_hash; - case DB_STRING: return &db_string_hash; - case DB_ISTRING: return &db_istring_hash; - default: - ShowError("db_default_hash: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_hash); + switch (type) { + case DB_INT: + return &db_int_hash; + case DB_UINT: + return &db_uint_hash; + case DB_STRING: + return &db_string_hash; + case DB_ISTRING: + return &db_istring_hash; + default: + ShowError("db_default_hash: Unknown database type %u\n", type); + return NULL; + } } /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed with {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser. @@ -2343,16 +2353,16 @@ DBHasher db_default_hash(DBType type) */ DBReleaser db_default_release(DBType type, DBOptions options) { - DB_COUNTSTAT(db_default_release); - options = db_fix_options(type, options); - if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_both; // Release both key and data - return &db_release_data; // Only release data - } - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_key; // Only release key - return &db_release_nothing; // Release nothing + DB_COUNTSTAT(db_default_release); + options = db_fix_options(type, options); + if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_both; // Release both key and data + return &db_release_data; // Only release data + } + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_key; // Only release key + return &db_release_nothing; // Release nothing } /** @@ -2368,16 +2378,20 @@ DBReleaser db_default_release(DBType type, DBOptions options) */ DBReleaser db_custom_release(DBRelease which) { - DB_COUNTSTAT(db_custom_release); - switch (which) { - case DB_RELEASE_NOTHING: return &db_release_nothing; - case DB_RELEASE_KEY: return &db_release_key; - case DB_RELEASE_DATA: return &db_release_data; - case DB_RELEASE_BOTH: return &db_release_both; - default: - ShowError("db_custom_release: Unknown release options %u\n", which); - return NULL; - } + DB_COUNTSTAT(db_custom_release); + switch (which) { + case DB_RELEASE_NOTHING: + return &db_release_nothing; + case DB_RELEASE_KEY: + return &db_release_key; + case DB_RELEASE_DATA: + return &db_release_data; + case DB_RELEASE_BOTH: + return &db_release_both; + default: + ShowError("db_custom_release: Unknown release options %u\n", which); + return NULL; + } } /** @@ -2388,75 +2402,83 @@ DBReleaser db_custom_release(DBRelease which) * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public * @see #DBMap_impl * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) +DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) { - DBMap_impl* db; - unsigned int i; + DBMap_impl *db; + unsigned int i; #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_alloc); - switch (type) { - case DB_INT: DB_COUNTSTAT(db_int_alloc); break; - case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break; - case DB_STRING: DB_COUNTSTAT(db_string_alloc); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; - } + DB_COUNTSTAT(db_alloc); + switch (type) { + case DB_INT: + DB_COUNTSTAT(db_int_alloc); + break; + case DB_UINT: + DB_COUNTSTAT(db_uint_alloc); + break; + case DB_STRING: + DB_COUNTSTAT(db_string_alloc); + break; + case DB_ISTRING: + DB_COUNTSTAT(db_istring_alloc); + break; + } #endif /* DB_ENABLE_STATS */ - CREATE(db, struct DBMap_impl, 1); - - options = db_fix_options(type, options); - /* Interface of the database */ - db->vtable.iterator = db_obj_iterator; - db->vtable.exists = db_obj_exists; - db->vtable.get = db_obj_get; - db->vtable.getall = db_obj_getall; - db->vtable.vgetall = db_obj_vgetall; - db->vtable.ensure = db_obj_ensure; - db->vtable.vensure = db_obj_vensure; - db->vtable.put = db_obj_put; - db->vtable.remove = db_obj_remove; - db->vtable.foreach = db_obj_foreach; - db->vtable.vforeach = db_obj_vforeach; - db->vtable.clear = db_obj_clear; - db->vtable.vclear = db_obj_vclear; - db->vtable.destroy = db_obj_destroy; - db->vtable.vdestroy = db_obj_vdestroy; - db->vtable.size = db_obj_size; - db->vtable.type = db_obj_type; - db->vtable.options = db_obj_options; - /* File and line of allocation */ - db->alloc_file = file; - db->alloc_line = line; - /* Lock system */ - db->free_list = NULL; - db->free_count = 0; - db->free_max = 0; - db->free_lock = 0; - /* Other */ - db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); - db->cmp = db_default_cmp(type); - db->hash = db_default_hash(type); - db->release = db_default_release(type, options); - for (i = 0; i < HASH_SIZE; i++) - db->ht[i] = NULL; - db->cache = NULL; - db->type = type; - db->options = options; - db->item_count = 0; - db->maxlen = maxlen; - db->global_lock = 0; - - if( db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING) ) - db->maxlen = UINT16_MAX; - - return &db->vtable; + CREATE(db, struct DBMap_impl, 1); + + options = db_fix_options(type, options); + /* Interface of the database */ + db->vtable.iterator = db_obj_iterator; + db->vtable.exists = db_obj_exists; + db->vtable.get = db_obj_get; + db->vtable.getall = db_obj_getall; + db->vtable.vgetall = db_obj_vgetall; + db->vtable.ensure = db_obj_ensure; + db->vtable.vensure = db_obj_vensure; + db->vtable.put = db_obj_put; + db->vtable.remove = db_obj_remove; + db->vtable.foreach = db_obj_foreach; + db->vtable.vforeach = db_obj_vforeach; + db->vtable.clear = db_obj_clear; + db->vtable.vclear = db_obj_vclear; + db->vtable.destroy = db_obj_destroy; + db->vtable.vdestroy = db_obj_vdestroy; + db->vtable.size = db_obj_size; + db->vtable.type = db_obj_type; + db->vtable.options = db_obj_options; + /* File and line of allocation */ + db->alloc_file = file; + db->alloc_line = line; + /* Lock system */ + db->free_list = NULL; + db->free_count = 0; + db->free_max = 0; + db->free_lock = 0; + /* Other */ + db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); + db->cmp = db_default_cmp(type); + db->hash = db_default_hash(type); + db->release = db_default_release(type, options); + for (i = 0; i < HASH_SIZE; i++) + db->ht[i] = NULL; + db->cache = NULL; + db->type = type; + db->options = options; + db->item_count = 0; + db->maxlen = maxlen; + db->global_lock = 0; + + if (db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING)) + db->maxlen = UINT16_MAX; + + return &db->vtable; } /** @@ -2467,11 +2489,11 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi */ DBKey db_i2key(int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_i2key); - ret.i = key; - return ret; + DB_COUNTSTAT(db_i2key); + ret.i = key; + return ret; } /** @@ -2482,11 +2504,11 @@ DBKey db_i2key(int key) */ DBKey db_ui2key(unsigned int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_ui2key); - ret.ui = key; - return ret; + DB_COUNTSTAT(db_ui2key); + ret.ui = key; + return ret; } /** @@ -2497,11 +2519,11 @@ DBKey db_ui2key(unsigned int key) */ DBKey db_str2key(const char *key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_str2key); - ret.str = key; - return ret; + DB_COUNTSTAT(db_str2key); + ret.str = key; + return ret; } /** @@ -2512,12 +2534,12 @@ DBKey db_str2key(const char *key) */ DBData db_i2data(int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_i2data); - ret.type = DB_DATA_INT; - ret.u.i = data; - return ret; + DB_COUNTSTAT(db_i2data); + ret.type = DB_DATA_INT; + ret.u.i = data; + return ret; } /** @@ -2528,12 +2550,12 @@ DBData db_i2data(int data) */ DBData db_ui2data(unsigned int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ui2data); - ret.type = DB_DATA_UINT; - ret.u.ui = data; - return ret; + DB_COUNTSTAT(db_ui2data); + ret.type = DB_DATA_UINT; + ret.u.ui = data; + return ret; } /** @@ -2544,12 +2566,12 @@ DBData db_ui2data(unsigned int data) */ DBData db_ptr2data(void *data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ptr2data); - ret.type = DB_DATA_PTR; - ret.u.ptr = data; - return ret; + DB_COUNTSTAT(db_ptr2data); + ret.type = DB_DATA_PTR; + ret.u.ptr = data; + return ret; } /** @@ -2561,10 +2583,10 @@ DBData db_ptr2data(void *data) */ int db_data2i(DBData *data) { - DB_COUNTSTAT(db_data2i); - if (data && DB_DATA_INT == data->type) - return data->u.i; - return 0; + DB_COUNTSTAT(db_data2i); + if (data && DB_DATA_INT == data->type) + return data->u.i; + return 0; } /** @@ -2576,10 +2598,10 @@ int db_data2i(DBData *data) */ unsigned int db_data2ui(DBData *data) { - DB_COUNTSTAT(db_data2ui); - if (data && DB_DATA_UINT == data->type) - return data->u.ui; - return 0; + DB_COUNTSTAT(db_data2ui); + if (data && DB_DATA_UINT == data->type) + return data->u.ui; + return 0; } /** @@ -2589,12 +2611,12 @@ unsigned int db_data2ui(DBData *data) * @return Void* value of the data. * @public */ -void* db_data2ptr(DBData *data) +void *db_data2ptr(DBData *data) { - DB_COUNTSTAT(db_data2ptr); - if (data && DB_DATA_PTR == data->type) - return data->u.ptr; - return NULL; + DB_COUNTSTAT(db_data2ptr); + if (data && DB_DATA_PTR == data->type) + return data->u.ptr; + return NULL; } /** @@ -2604,7 +2626,7 @@ void* db_data2ptr(DBData *data) */ void db_init(void) { - DB_COUNTSTAT(db_init); + DB_COUNTSTAT(db_init); } /** @@ -2615,208 +2637,208 @@ void db_init(void) void db_final(void) { #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_final); - ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" - "allocated %u, freed %u\n", - stats.db_node_alloc, stats.db_node_free); - ShowInfo(CL_WHITE"Database types"CL_RESET":\n" - "DB_INT : allocated %10u, destroyed %10u\n" - "DB_UINT : allocated %10u, destroyed %10u\n" - "DB_STRING : allocated %10u, destroyed %10u\n" - "DB_ISTRING : allocated %10u, destroyed %10u\n", - stats.db_int_alloc, stats.db_int_destroy, - stats.db_uint_alloc, stats.db_uint_destroy, - stats.db_string_alloc, stats.db_string_destroy, - stats.db_istring_alloc, stats.db_istring_destroy); - ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" - "db_rotate_left %10u, db_rotate_right %10u,\n" - "db_rebalance %10u, db_rebalance_erase %10u,\n" - "db_is_key_null %10u,\n" - "db_dup_key %10u, db_dup_key_free %10u,\n" - "db_free_add %10u, db_free_remove %10u,\n" - "db_free_lock %10u, db_free_unlock %10u,\n" - "db_int_cmp %10u, db_uint_cmp %10u,\n" - "db_string_cmp %10u, db_istring_cmp %10u,\n" - "db_int_hash %10u, db_uint_hash %10u,\n" - "db_string_hash %10u, db_istring_hash %10u,\n" - "db_release_nothing %10u, db_release_key %10u,\n" - "db_release_data %10u, db_release_both %10u,\n" - "dbit_first %10u, dbit_last %10u,\n" - "dbit_next %10u, dbit_prev %10u,\n" - "dbit_exists %10u, dbit_remove %10u,\n" - "dbit_destroy %10u, db_iterator %10u,\n" - "db_exits %10u, db_get %10u,\n" - "db_getall %10u, db_vgetall %10u,\n" - "db_ensure %10u, db_vensure %10u,\n" - "db_put %10u, db_remove %10u,\n" - "db_foreach %10u, db_vforeach %10u,\n" - "db_clear %10u, db_vclear %10u,\n" - "db_destroy %10u, db_vdestroy %10u,\n" - "db_size %10u, db_type %10u,\n" - "db_options %10u, db_fix_options %10u,\n" - "db_default_cmp %10u, db_default_hash %10u,\n" - "db_default_release %10u, db_custom_release %10u,\n" - "db_alloc %10u, db_i2key %10u,\n" - "db_ui2key %10u, db_str2key %10u,\n" - "db_i2data %10u, db_ui2data %10u,\n" - "db_ptr2data %10u, db_data2i %10u,\n" - "db_data2ui %10u, db_data2ptr %10u,\n" - "db_init %10u, db_final %10u\n", - stats.db_rotate_left, stats.db_rotate_right, - stats.db_rebalance, stats.db_rebalance_erase, - stats.db_is_key_null, - stats.db_dup_key, stats.db_dup_key_free, - stats.db_free_add, stats.db_free_remove, - stats.db_free_lock, stats.db_free_unlock, - stats.db_int_cmp, stats.db_uint_cmp, - stats.db_string_cmp, stats.db_istring_cmp, - stats.db_int_hash, stats.db_uint_hash, - stats.db_string_hash, stats.db_istring_hash, - stats.db_release_nothing, stats.db_release_key, - stats.db_release_data, stats.db_release_both, - stats.dbit_first, stats.dbit_last, - stats.dbit_next, stats.dbit_prev, - stats.dbit_exists, stats.dbit_remove, - stats.dbit_destroy, stats.db_iterator, - stats.db_exists, stats.db_get, - stats.db_getall, stats.db_vgetall, - stats.db_ensure, stats.db_vensure, - stats.db_put, stats.db_remove, - stats.db_foreach, stats.db_vforeach, - stats.db_clear, stats.db_vclear, - stats.db_destroy, stats.db_vdestroy, - stats.db_size, stats.db_type, - stats.db_options, stats.db_fix_options, - stats.db_default_cmp, stats.db_default_hash, - stats.db_default_release, stats.db_custom_release, - stats.db_alloc, stats.db_i2key, - stats.db_ui2key, stats.db_str2key, - stats.db_i2data, stats.db_ui2data, - stats.db_ptr2data, stats.db_data2i, - stats.db_data2ui, stats.db_data2ptr, - stats.db_init, stats.db_final); + DB_COUNTSTAT(db_final); + ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" + "allocated %u, freed %u\n", + stats.db_node_alloc, stats.db_node_free); + ShowInfo(CL_WHITE"Database types"CL_RESET":\n" + "DB_INT : allocated %10u, destroyed %10u\n" + "DB_UINT : allocated %10u, destroyed %10u\n" + "DB_STRING : allocated %10u, destroyed %10u\n" + "DB_ISTRING : allocated %10u, destroyed %10u\n", + stats.db_int_alloc, stats.db_int_destroy, + stats.db_uint_alloc, stats.db_uint_destroy, + stats.db_string_alloc, stats.db_string_destroy, + stats.db_istring_alloc, stats.db_istring_destroy); + ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" + "db_rotate_left %10u, db_rotate_right %10u,\n" + "db_rebalance %10u, db_rebalance_erase %10u,\n" + "db_is_key_null %10u,\n" + "db_dup_key %10u, db_dup_key_free %10u,\n" + "db_free_add %10u, db_free_remove %10u,\n" + "db_free_lock %10u, db_free_unlock %10u,\n" + "db_int_cmp %10u, db_uint_cmp %10u,\n" + "db_string_cmp %10u, db_istring_cmp %10u,\n" + "db_int_hash %10u, db_uint_hash %10u,\n" + "db_string_hash %10u, db_istring_hash %10u,\n" + "db_release_nothing %10u, db_release_key %10u,\n" + "db_release_data %10u, db_release_both %10u,\n" + "dbit_first %10u, dbit_last %10u,\n" + "dbit_next %10u, dbit_prev %10u,\n" + "dbit_exists %10u, dbit_remove %10u,\n" + "dbit_destroy %10u, db_iterator %10u,\n" + "db_exits %10u, db_get %10u,\n" + "db_getall %10u, db_vgetall %10u,\n" + "db_ensure %10u, db_vensure %10u,\n" + "db_put %10u, db_remove %10u,\n" + "db_foreach %10u, db_vforeach %10u,\n" + "db_clear %10u, db_vclear %10u,\n" + "db_destroy %10u, db_vdestroy %10u,\n" + "db_size %10u, db_type %10u,\n" + "db_options %10u, db_fix_options %10u,\n" + "db_default_cmp %10u, db_default_hash %10u,\n" + "db_default_release %10u, db_custom_release %10u,\n" + "db_alloc %10u, db_i2key %10u,\n" + "db_ui2key %10u, db_str2key %10u,\n" + "db_i2data %10u, db_ui2data %10u,\n" + "db_ptr2data %10u, db_data2i %10u,\n" + "db_data2ui %10u, db_data2ptr %10u,\n" + "db_init %10u, db_final %10u\n", + stats.db_rotate_left, stats.db_rotate_right, + stats.db_rebalance, stats.db_rebalance_erase, + stats.db_is_key_null, + stats.db_dup_key, stats.db_dup_key_free, + stats.db_free_add, stats.db_free_remove, + stats.db_free_lock, stats.db_free_unlock, + stats.db_int_cmp, stats.db_uint_cmp, + stats.db_string_cmp, stats.db_istring_cmp, + stats.db_int_hash, stats.db_uint_hash, + stats.db_string_hash, stats.db_istring_hash, + stats.db_release_nothing, stats.db_release_key, + stats.db_release_data, stats.db_release_both, + stats.dbit_first, stats.dbit_last, + stats.dbit_next, stats.dbit_prev, + stats.dbit_exists, stats.dbit_remove, + stats.dbit_destroy, stats.db_iterator, + stats.db_exists, stats.db_get, + stats.db_getall, stats.db_vgetall, + stats.db_ensure, stats.db_vensure, + stats.db_put, stats.db_remove, + stats.db_foreach, stats.db_vforeach, + stats.db_clear, stats.db_vclear, + stats.db_destroy, stats.db_vdestroy, + stats.db_size, stats.db_type, + stats.db_options, stats.db_fix_options, + stats.db_default_cmp, stats.db_default_hash, + stats.db_default_release, stats.db_custom_release, + stats.db_alloc, stats.db_i2key, + stats.db_ui2key, stats.db_str2key, + stats.db_i2data, stats.db_ui2data, + stats.db_ptr2data, stats.db_data2i, + stats.db_data2ui, stats.db_data2ptr, + stats.db_init, stats.db_final); #endif /* DB_ENABLE_STATS */ } // Link DB System - jAthena -void linkdb_insert( struct linkdb_node** head, void *key, void* data) -{ - struct linkdb_node *node; - if( head == NULL ) return ; - node = (struct linkdb_node*)aMalloc( sizeof(struct linkdb_node) ); - if( *head == NULL ) { - // first node - *head = node; - node->prev = NULL; - node->next = NULL; - } else { - // link nodes - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->key = key; - node->data = data; -} - -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) -{ - struct linkdb_node *node; - if( head == NULL ) return; - node = *head; - while ( node ) { - va_list args; - va_start(args, func); - func( node->key, node->data, args ); - va_end(args); - node = node->next; - } -} - -void* linkdb_search( struct linkdb_node** head, void *key) -{ - int n = 0; - struct linkdb_node *node; - if( head == NULL ) return NULL; - node = *head; - while( node ) { - if( node->key == key ) { - if( node->prev && n > 5 ) { - //Moving the head in order to improve processing efficiency - if(node->prev) node->prev->next = node->next; - if(node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - return node->data; - } - node = node->next; - n++; - } - return NULL; -} - -void* linkdb_erase( struct linkdb_node** head, void *key) -{ - struct linkdb_node *node; - if( head == NULL ) return NULL; - node = *head; - while( node ) { - if( node->key == key ) { - void *data = node->data; - if( node->prev == NULL ) - *head = node->next; - else - node->prev->next = node->next; - if( node->next ) - node->next->prev = node->prev; - aFree( node ); - return data; - } - node = node->next; - } - return NULL; -} - -void linkdb_replace( struct linkdb_node** head, void *key, void *data ) -{ - int n = 0; - struct linkdb_node *node; - if( head == NULL ) return ; - node = *head; - while( node ) { - if( node->key == key ) { - if( node->prev && n > 5 ) { - //Moving the head in order to improve processing efficiency - if(node->prev) node->prev->next = node->next; - if(node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->data = data; - return ; - } - node = node->next; - n++; - } - //Insert because it can not find - linkdb_insert( head, key, data ); -} - -void linkdb_final( struct linkdb_node** head ) -{ - struct linkdb_node *node, *node2; - if( head == NULL ) return ; - node = *head; - while( node ) { - node2 = node->next; - aFree( node ); - node = node2; - } - *head = NULL; +void linkdb_insert(struct linkdb_node **head, void *key, void *data) +{ + struct linkdb_node *node; + if (head == NULL) return ; + node = (struct linkdb_node *)aMalloc(sizeof(struct linkdb_node)); + if (*head == NULL) { + // first node + *head = node; + node->prev = NULL; + node->next = NULL; + } else { + // link nodes + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->key = key; + node->data = data; +} + +void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...) +{ + struct linkdb_node *node; + if (head == NULL) return; + node = *head; + while (node) { + va_list args; + va_start(args, func); + func(node->key, node->data, args); + va_end(args); + node = node->next; + } +} + +void *linkdb_search(struct linkdb_node **head, void *key) +{ + int n = 0; + struct linkdb_node *node; + if (head == NULL) return NULL; + node = *head; + while (node) { + if (node->key == key) { + if (node->prev && n > 5) { + //Moving the head in order to improve processing efficiency + if (node->prev) node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + return node->data; + } + node = node->next; + n++; + } + return NULL; +} + +void *linkdb_erase(struct linkdb_node **head, void *key) +{ + struct linkdb_node *node; + if (head == NULL) return NULL; + node = *head; + while (node) { + if (node->key == key) { + void *data = node->data; + if (node->prev == NULL) + *head = node->next; + else + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + aFree(node); + return data; + } + node = node->next; + } + return NULL; +} + +void linkdb_replace(struct linkdb_node **head, void *key, void *data) +{ + int n = 0; + struct linkdb_node *node; + if (head == NULL) return ; + node = *head; + while (node) { + if (node->key == key) { + if (node->prev && n > 5) { + //Moving the head in order to improve processing efficiency + if (node->prev) node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->data = data; + return ; + } + node = node->next; + n++; + } + //Insert because it can not find + linkdb_insert(head, key, data); +} + +void linkdb_final(struct linkdb_node **head) +{ + struct linkdb_node *node, *node2; + if (head == NULL) return ; + node = *head; + while (node) { + node2 = node->next; + aFree(node); + node = node2; + } + *head = NULL; } diff --git a/src/common/db.h b/src/common/db.h index 4fe6a93d6..eff3b775e 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -69,15 +69,15 @@ * @see #db_custom_release(DBRelease) */ typedef enum DBRelease { - DB_RELEASE_NOTHING = 0, - DB_RELEASE_KEY = 1, - DB_RELEASE_DATA = 2, - DB_RELEASE_BOTH = 3 + DB_RELEASE_NOTHING = 0, + DB_RELEASE_KEY = 1, + DB_RELEASE_DATA = 2, + DB_RELEASE_BOTH = 3 } DBRelease; /** * Supported types of database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_INT Uses int's for keys * @param DB_UINT Uses unsigned int's for keys @@ -93,22 +93,22 @@ typedef enum DBRelease { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBType { - DB_INT, - DB_UINT, - DB_STRING, - DB_ISTRING + DB_INT, + DB_UINT, + DB_STRING, + DB_ISTRING } DBType; /** * Bitfield of options that define the behaviour of the database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_OPT_BASE Base options: does not duplicate keys, releases nothing * and does not allow NULL keys or NULL data. - * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY + * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY * is defined, the real key is freed as soon as the entry is added. * @param DB_OPT_RELEASE_KEY Releases the key. - * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed + * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed * from the database. * WARNING: for funtions that return the data (like DBMap::remove), * a dangling pointer will be returned. @@ -121,13 +121,13 @@ typedef enum DBType { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBOptions { - DB_OPT_BASE = 0, - DB_OPT_DUP_KEY = 1, - DB_OPT_RELEASE_KEY = 2, - DB_OPT_RELEASE_DATA = 4, - DB_OPT_RELEASE_BOTH = 6, - DB_OPT_ALLOW_NULL_KEY = 8, - DB_OPT_ALLOW_NULL_DATA = 16, + DB_OPT_BASE = 0, + DB_OPT_DUP_KEY = 1, + DB_OPT_RELEASE_KEY = 2, + DB_OPT_RELEASE_DATA = 4, + DB_OPT_RELEASE_BOTH = 6, + DB_OPT_ALLOW_NULL_KEY = 8, + DB_OPT_ALLOW_NULL_DATA = 16, } DBOptions; /** @@ -142,9 +142,9 @@ typedef enum DBOptions { * @see DBMap#remove */ typedef union DBKey { - int i; - unsigned int ui; - const char *str; + int i; + unsigned int ui; + const char *str; } DBKey; /** @@ -156,9 +156,9 @@ typedef union DBKey { * @see #DBData */ typedef enum DBDataType { - DB_DATA_INT, - DB_DATA_UINT, - DB_DATA_PTR + DB_DATA_INT, + DB_DATA_UINT, + DB_DATA_PTR } DBDataType; /** @@ -171,16 +171,16 @@ typedef enum DBDataType { * @public */ typedef struct DBData { - DBDataType type; - union { - int i; - unsigned int ui; - void *ptr; - } u; + DBDataType type; + union { + int i; + unsigned int ui; + void *ptr; + } u; } DBData; /** - * Format of functions that create the data for the key when the entry doesn't + * Format of functions that create the data for the key when the entry doesn't * exist in the database yet. * @param key Key of the database entry * @param args Extra arguments of the function @@ -189,12 +189,12 @@ typedef struct DBData { * @see DBMap#vensure * @see DBMap#ensure */ -typedef DBData (*DBCreateData)(DBKey key, va_list args); +typedef DBData(*DBCreateData)(DBKey key, va_list args); /** - * Format of functions to be applied to an unspecified quantity of entries of + * Format of functions to be applied to an unspecified quantity of entries of * a database. - * Any function that applies this function to the database will return the sum + * Any function that applies this function to the database will return the sum * of values returned by this function. * @param key Key of the database entry * @param data Data of the database entry @@ -272,87 +272,86 @@ typedef struct DBMap DBMap; * Database iterator. * Supports forward iteration, backward iteration and removing entries from the database. * The iterator is initially positioned before the first entry of the database. - * While the iterator exists the database is locked internally, so invoke + * While the iterator exists the database is locked internally, so invoke * {@link DBIterator#destroy} as soon as possible. * @public * @see #DBMap */ -struct DBIterator -{ - - /** - * Fetches the first entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*first)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the last entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*last)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the next entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*next)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the previous entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*prev)(DBIterator* self, DBKey* out_key); - - /** - * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if - * the iterator is done. - * @param self Iterator - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBIterator* self); - - /** - * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry - * is fetched - * Puts data of the removed entry in out_data, if out_data is not NULL. - * @param self Iterator - * @param out_data Data of the removed entry. - * @return 1 if entry was removed, 0 otherwise - * @protected - * @see DBMap#remove - */ - int (*remove)(DBIterator* self, DBData *out_data); - - /** - * Destroys this iterator and unlocks the database. - * @param self Iterator - * @protected - */ - void (*destroy)(DBIterator* self); +struct DBIterator { + + /** + * Fetches the first entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*first)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the last entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*last)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the next entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*next)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the previous entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*prev)(DBIterator *self, DBKey *out_key); + + /** + * Returns true if the fetched entry exists. + * The databases entries might have NULL data, so use this to to test if + * the iterator is done. + * @param self Iterator + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBIterator *self); + + /** + * Removes the current entry from the database. + * NOTE: {@link DBIterator#exists} will return false until another entry + * is fetched + * Puts data of the removed entry in out_data, if out_data is not NULL. + * @param self Iterator + * @param out_data Data of the removed entry. + * @return 1 if entry was removed, 0 otherwise + * @protected + * @see DBMap#remove + */ + int (*remove)(DBIterator *self, DBData *out_data); + + /** + * Destroys this iterator and unlocks the database. + * @param self Iterator + * @protected + */ + void (*destroy)(DBIterator *self); }; @@ -364,235 +363,235 @@ struct DBIterator */ struct DBMap { - /** - * Returns a new iterator for this database. - * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal - * memory when unlocked, so destroy the iterator as soon as possible. - * @param self Database - * @return New iterator - * @protected - */ - DBIterator* (*iterator)(DBMap* self); - - /** - * Returns true if the entry exists. - * @param self Database - * @param key Key that identifies the entry - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBMap* self, DBKey key); - - /** - * Get the data of the entry identified by the key. - * @param self Database - * @param key Key that identifies the entry - * @return Data of the entry or NULL if not found - * @protected - */ - DBData* (*get)(DBMap* self, DBKey key); - - /** - * Just calls {@link DBMap#vgetall}. - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) - */ - unsigned int (*getall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, ...); - - /** - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) - */ - unsigned int (*vgetall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, va_list args); - - /** - * Just calls {@link DBMap#vensure}. - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param ... Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) - */ - DBData* (*ensure)(DBMap* self, DBKey key, DBCreateData create, ...); - - /** - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param args Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) - */ - DBData* (*vensure)(DBMap* self, DBKey key, DBCreateData create, va_list args); - - /** - * Put the data identified by the key in the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: Uses the new key, the old one is released. - * @param self Database - * @param key Key that identifies the data - * @param data Data to be put in the database - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*put)(DBMap* self, DBKey key, DBData data, DBData *out_data); - - /** - * Remove an entry from the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: The key (of the database) is released. - * @param self Database - * @param key Key that identifies the entry - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*remove)(DBMap* self, DBKey key, DBData *out_data); - - /** - * Just calls {@link DBMap#vforeach}. - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param ... Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#vforeach(DBMap*,DBApply,va_list) - */ - int (*foreach)(DBMap* self, DBApply func, ...); - - /** - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param args Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#foreach(DBMap*,DBApply,...) - */ - int (*vforeach)(DBMap* self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vclear}. - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vclear(DBMap*,DBApply,va_list) - */ - int (*clear)(DBMap* self, DBApply func, ...); - - /** - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#clear(DBMap*,DBApply,...) - */ - int (*vclear)(DBMap* self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vdestroy}. - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vdestroy(DBMap*,DBApply,va_list) - */ - int (*destroy)(DBMap* self, DBApply func, ...); - - /** - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#destroy(DBMap*,DBApply,...) - */ - int (*vdestroy)(DBMap* self, DBApply func, va_list args); - - /** - * Return the size of the database (number of items in the database). - * @param self Database - * @return Size of the database - * @protected - */ - unsigned int (*size)(DBMap* self); - - /** - * Return the type of the database. - * @param self Database - * @return Type of the database - * @protected - */ - DBType (*type)(DBMap* self); - - /** - * Return the options of the database. - * @param self Database - * @return Options of the database - * @protected - */ - DBOptions (*options)(DBMap* self); + /** + * Returns a new iterator for this database. + * The iterator keeps the database locked until it is destroyed. + * The database will keep functioning normally but will only free internal + * memory when unlocked, so destroy the iterator as soon as possible. + * @param self Database + * @return New iterator + * @protected + */ + DBIterator *(*iterator)(DBMap *self); + + /** + * Returns true if the entry exists. + * @param self Database + * @param key Key that identifies the entry + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBMap *self, DBKey key); + + /** + * Get the data of the entry identified by the key. + * @param self Database + * @param key Key that identifies the entry + * @return Data of the entry or NULL if not found + * @protected + */ + DBData *(*get)(DBMap *self, DBKey key); + + /** + * Just calls {@link DBMap#vgetall}. + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) + */ + unsigned int (*getall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...); + + /** + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) + */ + unsigned int (*vgetall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args); + + /** + * Just calls {@link DBMap#vensure}. + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param ... Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) + */ + DBData *(*ensure)(DBMap *self, DBKey key, DBCreateData create, ...); + + /** + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param args Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) + */ + DBData *(*vensure)(DBMap *self, DBKey key, DBCreateData create, va_list args); + + /** + * Put the data identified by the key in the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: Uses the new key, the old one is released. + * @param self Database + * @param key Key that identifies the data + * @param data Data to be put in the database + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*put)(DBMap *self, DBKey key, DBData data, DBData *out_data); + + /** + * Remove an entry from the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: The key (of the database) is released. + * @param self Database + * @param key Key that identifies the entry + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*remove)(DBMap *self, DBKey key, DBData *out_data); + + /** + * Just calls {@link DBMap#vforeach}. + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param ... Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#vforeach(DBMap*,DBApply,va_list) + */ + int (*foreach)(DBMap *self, DBApply func, ...); + + /** + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param args Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#foreach(DBMap*,DBApply,...) + */ + int (*vforeach)(DBMap *self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vclear}. + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vclear(DBMap*,DBApply,va_list) + */ + int (*clear)(DBMap *self, DBApply func, ...); + + /** + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#clear(DBMap*,DBApply,...) + */ + int (*vclear)(DBMap *self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vdestroy}. + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vdestroy(DBMap*,DBApply,va_list) + */ + int (*destroy)(DBMap *self, DBApply func, ...); + + /** + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#destroy(DBMap*,DBApply,...) + */ + int (*vdestroy)(DBMap *self, DBApply func, va_list args); + + /** + * Return the size of the database (number of items in the database). + * @param self Database + * @return Size of the database + * @protected + */ + unsigned int (*size)(DBMap *self); + + /** + * Return the type of the database. + * @param self Database + * @return Type of the database + * @protected + */ + DBType(*type)(DBMap *self); + + /** + * Return the options of the database. + * @param self Database + * @return Options of the database + * @protected + */ + DBOptions(*options)(DBMap *self); }; @@ -727,7 +726,7 @@ DBComparator db_default_cmp(DBType type); DBHasher db_default_hash(DBType type); /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser @@ -756,7 +755,7 @@ DBReleaser db_custom_release(DBRelease which); /** * Allocate a new database of the specified type. - * It uses the default comparator, hasher and releaser of the specified + * It uses the default comparator, hasher and releaser of the specified * database type and fixed options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before creating the database. @@ -764,7 +763,7 @@ DBReleaser db_custom_release(DBRelease which); * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public @@ -775,7 +774,7 @@ DBReleaser db_custom_release(DBRelease which); * @see #db_default_release(DBType,DBOptions) * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); +DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); /** * Manual cast from 'int' to the union DBKey. @@ -850,7 +849,7 @@ unsigned int db_data2ui(DBData *data); * @return Void* value of the data. * @public */ -void* db_data2ptr(DBData *data); +void *db_data2ptr(DBData *data); /** * Initialize the database system. @@ -869,20 +868,20 @@ void db_final(void); // Link DB System - From jAthena struct linkdb_node { - struct linkdb_node *next; - struct linkdb_node *prev; - void *key; - void *data; + struct linkdb_node *next; + struct linkdb_node *prev; + void *key; + void *data; }; -typedef void (*LinkDBFunc)(void* key, void* data, va_list args); +typedef void (*LinkDBFunc)(void *key, void *data, va_list args); -void linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない -void linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する -void* linkdb_search ( struct linkdb_node** head, void *key); -void* linkdb_erase ( struct linkdb_node** head, void *key); -void linkdb_final ( struct linkdb_node** head ); -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); +void linkdb_insert(struct linkdb_node **head, void *key, void *data); // 重複を考慮しない +void linkdb_replace(struct linkdb_node **head, void *key, void *data); // 重複を考慮する +void *linkdb_search(struct linkdb_node **head, void *key); +void *linkdb_erase(struct linkdb_node **head, void *key); +void linkdb_final(struct linkdb_node **head); +void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); @@ -894,11 +893,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __var Index variable /// @param __cmp Expression that returns true when the target entry is found #define ARR_FIND(__start, __end, __var, __cmp) \ - do{ \ - for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ - if( __cmp ) \ - break; \ - }while(0) + do{ \ + for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ + if( __cmp ) \ + break; \ + }while(0) @@ -912,18 +911,18 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVE(__from, __to, __arr, __type) \ - do{ \ - if( (__from) != (__to) ) \ - { \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - if( (__from) < (__to) ) \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - else if( (__from) > (__to) ) \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - } \ - }while(0) + do{ \ + if( (__from) != (__to) ) \ + { \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + if( (__from) < (__to) ) \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + else if( (__from) > (__to) ) \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + } \ + }while(0) @@ -935,12 +934,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVERIGHT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -952,12 +951,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVELEFT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -971,11 +970,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __type Type of data #define VECTOR_DECL(__type) \ - struct { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -984,11 +983,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __name Structure name /// @param __type Type of data #define VECTOR_STRUCT_DECL(__name,__type) \ - struct __name { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct __name { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -997,7 +996,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __type Type of data /// @param __var Variable name #define VECTOR_VAR(__type,__var) \ - VECTOR_DECL(__type) __var = {0,0,NULL} + VECTOR_DECL(__type) __var = {0,0,NULL} @@ -1006,7 +1005,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __name Structure name /// @param __var Variable name #define VECTOR_STRUCT_VAR(__name,__var) \ - struct __name __var = {0,0,NULL} + struct __name __var = {0,0,NULL} @@ -1014,7 +1013,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_INIT(__vec) \ - memset(&(__vec), 0, sizeof(__vec)) + memset(&(__vec), 0, sizeof(__vec)) @@ -1023,7 +1022,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Array of values #define VECTOR_DATA(__vec) \ - ( (__vec)._data_ ) + ( (__vec)._data_ ) @@ -1032,7 +1031,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Length #define VECTOR_LENGTH(__vec) \ - ( (__vec)._len_ ) + ( (__vec)._len_ ) @@ -1041,7 +1040,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Capacity #define VECTOR_CAPACITY(__vec) \ - ( (__vec)._max_ ) + ( (__vec)._max_ ) @@ -1052,7 +1051,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @return Value #define VECTOR_INDEX(__vec,__idx) \ - ( VECTOR_DATA(__vec)[__idx] ) + ( VECTOR_DATA(__vec)[__idx] ) @@ -1062,7 +1061,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return First value #define VECTOR_FIRST(__vec) \ - ( VECTOR_INDEX(__vec,0) ) + ( VECTOR_INDEX(__vec,0) ) @@ -1072,7 +1071,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Last value #define VECTOR_LAST(__vec) \ - ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) + ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) @@ -1082,27 +1081,27 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __n Size #define VECTOR_RESIZE(__vec,__n) \ - do{ \ - if( (__n) > VECTOR_CAPACITY(__vec) ) \ - { /* increase size */ \ - if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ - else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - } \ - else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ - { /* clear vector */ \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - else if( (__n) < VECTOR_CAPACITY(__vec) ) \ - { /* reduce size */ \ - SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ - } \ - }while(0) + do{ \ + if( (__n) > VECTOR_CAPACITY(__vec) ) \ + { /* increase size */ \ + if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ + else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + } \ + else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ + { /* clear vector */ \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + else if( (__n) < VECTOR_CAPACITY(__vec) ) \ + { /* reduce size */ \ + SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ + } \ + }while(0) @@ -1113,11 +1112,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __n Empty positions /// @param __step Increase #define VECTOR_ENSURE(__vec,__n,__step) \ - do{ \ - size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ - while( (__n) > _empty_ ) _empty_ += (__step); \ - if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ - }while(0) + do{ \ + size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ + while( (__n) > _empty_ ) _empty_ += (__step); \ + if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ + }while(0) @@ -1127,12 +1126,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __idx Index #define VECTOR_INSERTZEROED(__vec,__idx) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1143,12 +1142,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __val Value #define VECTOR_INSERT(__vec,__idx,__val) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1159,7 +1158,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __val Value #define VECTOR_INSERTCOPY(__vec,__idx,__val) \ - VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) + VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) @@ -1171,12 +1170,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_INSERTARRAY(__vec,__idx,__pval,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1185,10 +1184,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_PUSHZEROED(__vec) \ - do{ \ - memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) /// Inserts a value in the end of the vector. (using the '=' operator) @@ -1197,10 +1196,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSH(__vec,__val) \ - do{ \ - VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1210,7 +1209,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSHCOPY(__vec,__val) \ - VECTOR_PUSHARRAY(__vec,&(__val),1) + VECTOR_PUSHARRAY(__vec,&(__val),1) @@ -1221,10 +1220,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_PUSHARRAY(__vec,__pval,__n) \ - do{ \ - memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1234,7 +1233,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Removed value #define VECTOR_POP(__vec) \ - ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) + ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) @@ -1245,7 +1244,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __n Number of pops /// @return Last removed value #define VECTOR_POPN(__vec,__n) \ - ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) + ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) @@ -1255,7 +1254,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __idx Index #define VECTOR_ERASE(__vec,__idx) \ - VECTOR_ERASEN(__vec,__idx,1) + VECTOR_ERASEN(__vec,__idx,1) @@ -1266,11 +1265,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __n Number of values #define VECTOR_ERASEN(__vec,__idx,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ + }while(0) @@ -1278,14 +1277,14 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_CLEAR(__vec) \ - do{ \ - if( VECTOR_CAPACITY(__vec) ) \ - { \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - }while(0) + do{ \ + if( VECTOR_CAPACITY(__vec) ) \ + { \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + }while(0) @@ -1388,18 +1387,18 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __val Value /// @param __topcmp Comparator #define BHEAP_PUSH(__heap,__val,__topcmp) \ - do{ \ - size_t _i_ = VECTOR_LENGTH(__heap); \ - VECTOR_PUSH(__heap,__val); /* insert at end */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - }while(0) + do{ \ + size_t _i_ = VECTOR_LENGTH(__heap); \ + VECTOR_PUSH(__heap,__val); /* insert at end */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + }while(0) @@ -1429,36 +1428,36 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __topcmp Comparator #define BHEAP_POPINDEX(__heap,__idx,__topcmp) \ - do{ \ - size_t _i_ = __idx; \ - VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - while( _i_ < VECTOR_LENGTH(__heap) ) \ - { /* restore heap property in childs */ \ - size_t _lchild_ = _i_*2 + 1; \ - size_t _rchild_ = _i_*2 + 2; \ - if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ - (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ - break; /* done */ \ - else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ - { /* left child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ - _i_ = _lchild_; \ - } \ - else \ - { /* right child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ - _i_ = _rchild_; \ - } \ - } \ - }while(0) + do{ \ + size_t _i_ = __idx; \ + VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + while( _i_ < VECTOR_LENGTH(__heap) ) \ + { /* restore heap property in childs */ \ + size_t _lchild_ = _i_*2 + 1; \ + size_t _rchild_ = _i_*2 + 2; \ + if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ + (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ + break; /* done */ \ + else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ + { /* left child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ + _i_ = _lchild_; \ + } \ + else \ + { /* right child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ + _i_ = _rchild_; \ + } \ + } \ + }while(0) diff --git a/src/common/des.c b/src/common/des.c index 917fc33e0..f2347f3c4 100644 --- a/src/common/des.c +++ b/src/common/des.c @@ -12,207 +12,201 @@ /// Bitmask for accessing individual bits of a byte. static const uint8_t mask[8] = { - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /// Initial permutation (IP). -static void IP(BIT64* src) +static void IP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t ip_table[64] = { - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(ip_table); ++i ) - { - uint8_t j = ip_table[i] - 1; - if( src->b[(j >> 3) & 7] & mask[j & 7] ) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t ip_table[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(ip_table); ++i) { + uint8_t j = ip_table[i] - 1; + if (src->b[(j >> 3) & 7] & mask[j & 7]) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Final permutation (IP^-1). -static void FP(BIT64* src) +static void FP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t fp_table[64] = { - 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(fp_table); ++i ) - { - uint8_t j = fp_table[i] - 1; - if( src->b[(j >> 3) & 7] & mask[j & 7] ) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t fp_table[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(fp_table); ++i) { + uint8_t j = fp_table[i] - 1; + if (src->b[(j >> 3) & 7] & mask[j & 7]) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Expansion (E). /// Expands upper four 8-bits (32b) into eight 6-bits (48b). -static void E(BIT64* src) +static void E(BIT64 *src) { - BIT64 tmp = {{0}}; - -if( false ) -{// original - static const uint8_t expand_table[48] = { - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(expand_table); ++i ) - { - uint8_t j = expand_table[i] - 1; - if( src->b[j / 8 + 4] & mask[j % 8] ) - tmp .b[i / 6 + 0] |= mask[i % 6]; - } -} -else -{// optimized - tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr - tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n - tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj - tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f - tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb - tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 - tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 - tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v -} - - *src = tmp; + BIT64 tmp = {{0}}; + + if (false) { + // original + static const uint8_t expand_table[48] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(expand_table); ++i) { + uint8_t j = expand_table[i] - 1; + if (src->b[j / 8 + 4] & mask[j % 8]) + tmp .b[i / 6 + 0] |= mask[i % 6]; + } + } else { + // optimized + tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr + tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n + tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj + tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f + tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb + tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 + tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 + tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v + } + + *src = tmp; } /// Transposition (P-BOX). -static void TP(BIT64* src) +static void TP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t tp_table[32] = { - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(tp_table); ++i ) - { - uint8_t j = tp_table[i] - 1; - if( src->b[(j >> 3) + 0] & mask[j & 7] ) - tmp .b[(i >> 3) + 4] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t tp_table[32] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(tp_table); ++i) { + uint8_t j = tp_table[i] - 1; + if (src->b[(j >> 3) + 0] & mask[j & 7]) + tmp .b[(i >> 3) + 4] |= mask[i & 7]; + } + + *src = tmp; } /// Substitution boxes (S-boxes). /// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast). -static void SBOX(BIT64* src) +static void SBOX(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t s_table[4][64] = { - { - 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, - 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, - 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, - 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, - },{ - 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, - 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, - 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, - 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, - },{ - 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, - 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, - 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, - 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, - },{ - 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, - 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, - 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, - 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, - } - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(s_table); ++i ) - { - tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) - | (s_table[i][src->b[i*2+1]] & 0x0f); - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t s_table[4][64] = { + { + 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, + 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, + 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, + 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, + },{ + 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, + 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, + 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, + 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, + },{ + 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, + 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, + 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, + 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, + },{ + 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, + 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, + 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, + 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, + } + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(s_table); ++i) { + tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) + | (s_table[i][src->b[i*2+1]] & 0x0f); + } + + *src = tmp; } /// DES round function. /// XORs src[0..3] with TP(SBOX(E(src[4..7]))). -static void RoundFunction(BIT64* src) +static void RoundFunction(BIT64 *src) { - BIT64 tmp = *src; - E(&tmp); - SBOX(&tmp); - TP(&tmp); - - src->b[0] ^= tmp.b[4]; - src->b[1] ^= tmp.b[5]; - src->b[2] ^= tmp.b[6]; - src->b[3] ^= tmp.b[7]; + BIT64 tmp = *src; + E(&tmp); + SBOX(&tmp); + TP(&tmp); + + src->b[0] ^= tmp.b[4]; + src->b[1] ^= tmp.b[5]; + src->b[2] ^= tmp.b[6]; + src->b[3] ^= tmp.b[7]; } -void des_decrypt_block(BIT64* block) +void des_decrypt_block(BIT64 *block) { - IP(block); - RoundFunction(block); - FP(block); + IP(block); + RoundFunction(block); + FP(block); } -void des_decrypt(unsigned char* data, size_t size) +void des_decrypt(unsigned char *data, size_t size) { - BIT64* p = (BIT64*)data; - size_t i; + BIT64 *p = (BIT64 *)data; + size_t i; - for( i = 0; i*8 < size; i += 8 ) - des_decrypt_block(p); + for (i = 0; i*8 < size; i += 8) + des_decrypt_block(p); } diff --git a/src/common/des.h b/src/common/des.h index e42136436..a13a17165 100644 --- a/src/common/des.h +++ b/src/common/des.h @@ -1,15 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _DES_H_ -#define _DES_H_ +#ifndef _DES_H_ +#define _DES_H_ /// One 64-bit block. -typedef struct BIT64 { uint8_t b[8]; } BIT64; +typedef struct BIT64 { + uint8_t b[8]; +} BIT64; -void des_decrypt_block(BIT64* block); -void des_decrypt(unsigned char* data, size_t size); +void des_decrypt_block(BIT64 *block); +void des_decrypt(unsigned char *data, size_t size); #endif // _DES_H_ diff --git a/src/common/ers.c b/src/common/ers.c index b94b0888d..d75f23f6f 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -51,54 +51,51 @@ #define ERS_ROOT_SIZE 256 #define ERS_BLOCK_ENTRIES 4096 -struct ers_list -{ - struct ers_list *Next; +struct ers_list { + struct ers_list *Next; }; -typedef struct ers_cache -{ - // Allocated object size, including ers_list size - unsigned int ObjectSize; +typedef struct ers_cache { + // Allocated object size, including ers_list size + unsigned int ObjectSize; + + // Number of ers_instances referencing this + int ReferenceCount; - // Number of ers_instances referencing this - int ReferenceCount; + // Reuse linked list + struct ers_list *ReuseList; - // Reuse linked list - struct ers_list *ReuseList; + // Memory blocks array + unsigned char **Blocks; - // Memory blocks array - unsigned char **Blocks; + // Max number of blocks + unsigned int Max; - // Max number of blocks - unsigned int Max; + // Free objects count + unsigned int Free; - // Free objects count - unsigned int Free; - - // Used objects count - unsigned int Used; + // Used objects count + unsigned int Used; - // Linked list - struct ers_cache *Next, *Prev; + // Linked list + struct ers_cache *Next, *Prev; } ers_cache_t; -typedef struct -{ - // Interface to ERS - struct eri VTable; - - // Name, used for debbuging purpouses - char *Name; +typedef struct { + // Interface to ERS + struct eri VTable; + + // Name, used for debbuging purpouses + char *Name; - // Misc options - enum ERSOptions Options; + // Misc options + enum ERSOptions Options; - // Our cache - ers_cache_t *Cache; + // Our cache + ers_cache_t *Cache; - // Count of objects in use, used for detecting memory leaks - unsigned int Count; + // Count of objects in use, used for detecting memory leaks + unsigned int Count; } ers_instance_t; @@ -107,186 +104,171 @@ static ers_cache_t *CacheList; static ers_cache_t *ers_find_cache(unsigned int size) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - if (cache->ObjectSize == size) - return cache; - - CREATE(cache, ers_cache_t, 1); - cache->ObjectSize = size; - cache->ReferenceCount = 0; - cache->ReuseList = NULL; - cache->Blocks = NULL; - cache->Free = 0; - cache->Used = 0; - cache->Max = 0; - - if (CacheList == NULL) - { - CacheList = cache; - } - else - { - cache->Next = CacheList; - cache->Next->Prev = cache; - CacheList = cache; - CacheList->Prev = NULL; - } - - return cache; + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + if (cache->ObjectSize == size) + return cache; + + CREATE(cache, ers_cache_t, 1); + cache->ObjectSize = size; + cache->ReferenceCount = 0; + cache->ReuseList = NULL; + cache->Blocks = NULL; + cache->Free = 0; + cache->Used = 0; + cache->Max = 0; + + if (CacheList == NULL) { + CacheList = cache; + } else { + cache->Next = CacheList; + cache->Next->Prev = cache; + CacheList = cache; + CacheList->Prev = NULL; + } + + return cache; } static void ers_free_cache(ers_cache_t *cache, bool remove) { - unsigned int i; + unsigned int i; - for (i = 0; i < cache->Used; i++) - aFree(cache->Blocks[i]); + for (i = 0; i < cache->Used; i++) + aFree(cache->Blocks[i]); - if (cache->Next) - cache->Next->Prev = cache->Prev; + if (cache->Next) + cache->Next->Prev = cache->Prev; - if (cache->Prev) - cache->Prev->Next = cache->Next; - else - CacheList = cache->Next; + if (cache->Prev) + cache->Prev->Next = cache->Next; + else + CacheList = cache->Next; - aFree(cache->Blocks); - aFree(cache); + aFree(cache->Blocks); + aFree(cache); } static void *ers_obj_alloc_entry(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; - void *ret; - - if (instance == NULL) - { - ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); - return NULL; - } - - if (instance->Cache->ReuseList != NULL) - { - ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); - instance->Cache->ReuseList = instance->Cache->ReuseList->Next; - } - else if (instance->Cache->Free > 0) - { - instance->Cache->Free--; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - else - { - if (instance->Cache->Used == instance->Cache->Max) - { - instance->Cache->Max = (instance->Cache->Max * 4) + 3; - RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); - } - - CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); - instance->Cache->Used++; - - instance->Cache->Free = ERS_BLOCK_ENTRIES -1; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - - instance->Count++; - - return ret; + ers_instance_t *instance = (ers_instance_t *)self; + void *ret; + + if (instance == NULL) { + ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); + return NULL; + } + + if (instance->Cache->ReuseList != NULL) { + ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); + instance->Cache->ReuseList = instance->Cache->ReuseList->Next; + } else if (instance->Cache->Free > 0) { + instance->Cache->Free--; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } else { + if (instance->Cache->Used == instance->Cache->Max) { + instance->Cache->Max = (instance->Cache->Max * 4) + 3; + RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); + } + + CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); + instance->Cache->Used++; + + instance->Cache->Free = ERS_BLOCK_ENTRIES -1; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } + + instance->Count++; + + return ret; } static void ers_obj_free_entry(ERS self, void *entry) { - ers_instance_t *instance = (ers_instance_t *)self; - struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); - - if (instance == NULL) - { - ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); - return; - } - else if (entry == NULL) - { - ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); - return; - } - - reuse->Next = instance->Cache->ReuseList; - instance->Cache->ReuseList = reuse; - instance->Count--; + ers_instance_t *instance = (ers_instance_t *)self; + struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); + + if (instance == NULL) { + ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); + return; + } else if (entry == NULL) { + ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); + return; + } + + reuse->Next = instance->Cache->ReuseList; + instance->Cache->ReuseList = reuse; + instance->Count--; } static size_t ers_obj_entry_size(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) - { - ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); - return 0; - } + if (instance == NULL) { + ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); + return 0; + } - return instance->Cache->ObjectSize; + return instance->Cache->ObjectSize; } static void ers_obj_destroy(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) - { - ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); - return; - } + if (instance == NULL) { + ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); + return; + } - if (instance->Count > 0) - if (!(instance->Options & ERS_OPT_CLEAR)) - ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); + if (instance->Count > 0) + if (!(instance->Options & ERS_OPT_CLEAR)) + ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); - if (--instance->Cache->ReferenceCount <= 0) - ers_free_cache(instance->Cache, true); + if (--instance->Cache->ReferenceCount <= 0) + ers_free_cache(instance->Cache, true); - aFree(instance); + aFree(instance); } ERS ers_new(uint32 size, char *name, enum ERSOptions options) { - ers_instance_t *instance; - CREATE(instance, ers_instance_t, 1); + ers_instance_t *instance; + CREATE(instance, ers_instance_t, 1); - size += sizeof(struct ers_list); - if (size % ERS_ALIGNED) - size += ERS_ALIGNED - size % ERS_ALIGNED; + size += sizeof(struct ers_list); + if (size % ERS_ALIGNED) + size += ERS_ALIGNED - size % ERS_ALIGNED; - instance->VTable.alloc = ers_obj_alloc_entry; - instance->VTable.free = ers_obj_free_entry; - instance->VTable.entry_size = ers_obj_entry_size; - instance->VTable.destroy = ers_obj_destroy; + instance->VTable.alloc = ers_obj_alloc_entry; + instance->VTable.free = ers_obj_free_entry; + instance->VTable.entry_size = ers_obj_entry_size; + instance->VTable.destroy = ers_obj_destroy; - instance->Name = name; - instance->Options = options; + instance->Name = name; + instance->Options = options; - instance->Cache = ers_find_cache(size); - instance->Cache->ReferenceCount++; + instance->Cache = ers_find_cache(size); + instance->Cache->ReferenceCount++; - instance->Count = 0; + instance->Count = 0; - return &instance->VTable; + return &instance->VTable; } void ers_report(void) { - // FIXME: Someone use this? Is it really needed? + // FIXME: Someone use this? Is it really needed? } void ers_force_destroy_all(void) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - ers_free_cache(cache, false); + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + ers_free_cache(cache, false); } #endif diff --git a/src/common/ers.h b/src/common/ers.h index dc66af5ef..c8fe2b4af 100644 --- a/src/common/ers.h +++ b/src/common/ers.h @@ -55,7 +55,7 @@ /** * Define this to disable the Entry Reusage System. * All code except the typedef of ERInterface will be disabled. - * To allow a smooth transition, + * To allow a smooth transition, */ //#define DISABLE_ERS @@ -63,16 +63,16 @@ * Entries are aligned to ERS_ALIGNED bytes in the blocks of entries. * By default it aligns to one byte, using the "natural order" of the entries. * This should NEVER be set to zero or less. - * If greater than one, some memory can be wasted. This should never be needed + * If greater than one, some memory can be wasted. This should never be needed * but is here just in case some aligment issues arise. */ #ifndef ERS_ALIGNED -# define ERS_ALIGNED 1 +# define ERS_ALIGNED 1 #endif /* not ERS_ALIGN_ENTRY */ enum ERSOptions { - ERS_OPT_NONE = 0, - ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ + ERS_OPT_NONE = 0, + ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ }; /** @@ -84,65 +84,65 @@ enum ERSOptions { */ typedef struct eri { - /** - * Allocate an entry from this entry manager. - * If there are reusable entries available, it reuses one instead. - * @param self Interface of the entry manager - * @return An entry - */ - void *(*alloc)(struct eri *self); - - /** - * Free an entry allocated from this manager. - * WARNING: Does not check if the entry was allocated by this manager. - * Freeing such an entry can lead to unexpected behaviour. - * @param self Interface of the entry manager - * @param entry Entry to be freed - */ - void (*free)(struct eri *self, void *entry); - - /** - * Return the size of the entries allocated from this manager. - * @param self Interface of the entry manager - * @return Size of the entries of this manager in bytes - */ - size_t (*entry_size)(struct eri *self); - - /** - * Destroy this instance of the manager. - * The manager is actually only destroyed when all the instances are destroyed. - * When destroying the manager a warning is shown if the manager has - * missing/extra entries. - * @param self Interface of the entry manager - */ - void (*destroy)(struct eri *self); + /** + * Allocate an entry from this entry manager. + * If there are reusable entries available, it reuses one instead. + * @param self Interface of the entry manager + * @return An entry + */ + void *(*alloc)(struct eri *self); + + /** + * Free an entry allocated from this manager. + * WARNING: Does not check if the entry was allocated by this manager. + * Freeing such an entry can lead to unexpected behaviour. + * @param self Interface of the entry manager + * @param entry Entry to be freed + */ + void (*free)(struct eri *self, void *entry); + + /** + * Return the size of the entries allocated from this manager. + * @param self Interface of the entry manager + * @return Size of the entries of this manager in bytes + */ + size_t (*entry_size)(struct eri *self); + + /** + * Destroy this instance of the manager. + * The manager is actually only destroyed when all the instances are destroyed. + * When destroying the manager a warning is shown if the manager has + * missing/extra entries. + * @param self Interface of the entry manager + */ + void (*destroy)(struct eri *self); } *ERS; #ifdef DISABLE_ERS // Use memory manager to allocate/free and disable other interface functions -# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) -# define ers_free(obj,entry) aFree(entry) -# define ers_entry_size(obj) (size_t)0 -# define ers_destroy(obj) +# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) +# define ers_free(obj,entry) aFree(entry) +# define ers_entry_size(obj) (size_t)0 +# define ers_destroy(obj) // Disable the public functions -# define ers_new(size,name,options) NULL -# define ers_report() -# define ers_force_destroy_all() +# define ers_new(size,name,options) NULL +# define ers_report() +# define ers_force_destroy_all() #else /* not DISABLE_ERS */ -// These defines should be used to allow the code to keep working whenever +// These defines should be used to allow the code to keep working whenever // the system is disabled -# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) -# define ers_free(obj,entry) (obj)->free((obj),(entry)) -# define ers_entry_size(obj) (obj)->entry_size(obj) -# define ers_destroy(obj) (obj)->destroy(obj) +# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) +# define ers_free(obj,entry) (obj)->free((obj),(entry)) +# define ers_entry_size(obj) (obj)->entry_size(obj) +# define ers_destroy(obj) (obj)->destroy(obj) /** * Get a new instance of the manager that handles the specified entry size. * Size has to greater than 0. - * If the specified size is smaller than a pointer, the size of a pointer is + * If the specified size is smaller than a pointer, the size of a pointer is * used instead. - * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of + * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of * ERS_ALIGNED that is greater or equal to size is what's actually used. * @param The requested size of the entry in bytes * @return Interface of the object @@ -152,7 +152,7 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options); /** * Print a report about the current state of the Entry Reusage System. * Shows information about the global system and each entry manager. - * The number of entries are checked and a warning is shown if extra reusable + * The number of entries are checked and a warning is shown if extra reusable * entries are found. * The extra entries are included in the count of reusable entries. */ @@ -163,7 +163,7 @@ void ers_report(void); * The system is left as if no instances or entries had ever been allocated. * All previous entries and instances of the managers become invalid. * The use of this is NOT recommended. - * It should only be used in extreme situations to make shure all the memory + * It should only be used in extreme situations to make shure all the memory * allocated by this system is released. */ void ers_force_destroy_all(void); diff --git a/src/common/evdp.h b/src/common/evdp.h index bc3454686..c9cff9e2b 100644 --- a/src/common/evdp.h +++ b/src/common/evdp.h @@ -8,27 +8,27 @@ typedef struct EVDP_DATA EVDP_DATA; //#idef EVDP_EPOLL #include -struct EVDP_DATA{ - struct epoll_event ev_data; - bool ev_added; +struct EVDP_DATA { + struct epoll_event ev_data; + bool ev_added; }; //#endif -enum EVDP_EVENTFLAGS{ - EVDP_EVENT_IN = 1, // Incomming data - EVDP_EVENT_OUT = 2, // Connection accepts writing. - EVDP_EVENT_HUP = 4 // Connection Closed. +enum EVDP_EVENTFLAGS { + EVDP_EVENT_IN = 1, // Incomming data + EVDP_EVENT_OUT = 2, // Connection accepts writing. + EVDP_EVENT_HUP = 4 // Connection Closed. }; -typedef struct EVDP_EVENT{ - int32 events; // due to performance reasons, this should be the first member. - int32 fd; // Connection Identifier +typedef struct EVDP_EVENT { + int32 events; // due to performance reasons, this should be the first member. + int32 fd; // Connection Identifier } EVDP_EVENT; -/** +/** * Network Event Dispatcher Initialization / Finalization routines */ void evdp_init(); @@ -38,56 +38,56 @@ void evdp_final(); /** * Will Wait for events. * - * @param *out_ev pointer to array in size at least of max_events. - * @param max_events max no of events to report with this call (coalesc) - * @param timeout_ticks max time to wait in ticks (milliseconds) + * @param *out_ev pointer to array in size at least of max_events. + * @param max_events max no of events to report with this call (coalesc) + * @param timeout_ticks max time to wait in ticks (milliseconds) * * @Note: - * The function will block until an event has occured on one of the monitored connections - * or the timeout of timeout_ticks has passed by. - * Upon successfull call (changed connections) this function will write the connection - * Identifier & event to the out_fds array. + * The function will block until an event has occured on one of the monitored connections + * or the timeout of timeout_ticks has passed by. + * Upon successfull call (changed connections) this function will write the connection + * Identifier & event to the out_fds array. * - * @return 0 -> Timeout, > 0 no of changed connections. + * @return 0 -> Timeout, > 0 no of changed connections. */ -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); -/** +/** * Applys the given mask on the given connection. - * - * @param fd connection identifier - * @param *ep event data pointer for the connection - * @param mask new event mask we're monitoring for. + * + * @param fd connection identifier + * @param *ep event data pointer for the connection + * @param mask new event mask we're monitoring for. */ -//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); +//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); -/** +/** * Adds a connection (listner) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * - * @note: - * Listener type sockets are edge triggered, (see epoll manual for more information) + * @note: + * Listener type sockets are edge triggered, (see epoll manual for more information) * - This basicaly means that youll receive one event, adn you have to accept until accept returns an error (nothing to accept) * * MONITORS by default: IN - * + * * @return success indicator. - */ + */ bool evdp_addlistener(int32 fd, EVDP_DATA *ep); /** * Adds a connection (client connectioN) to the event notification system * - * @param fd connection identifier - * @param *ep event data pointr for the connection - * + * @param fd connection identifier + * @param *ep event data pointr for the connection + * * @note: - * - * MONITORS by default: IN, HUP + * + * MONITORS by default: IN, HUP * * @return success indicator. */ @@ -96,17 +96,17 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); /** * Adds a connection (pending / outgoing connection!) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. * * @note: - * Outgoing connection type sockets are getting monitored for connection established - * successfull - * - if the connection has been established - we're generitng a writable notification .. (send) - * this is typical for BSD / posix conform network stacks. - * - Additinionally its edge triggered. + * Outgoing connection type sockets are getting monitored for connection established + * successfull + * - if the connection has been established - we're generitng a writable notification .. (send) + * this is typical for BSD / posix conform network stacks. + * - Additinionally its edge triggered. * - * @see evdp_outgoingconnection_established + * @see evdp_outgoingconnection_established * * * @return success indicator @@ -114,14 +114,14 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); bool evdp_addconnecting(int32 fd, EVDP_DATA *ep); /** - * Adds an outgoing connection to the normal event notification system after it has been successfully established. - * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. - - * @note - * after this call, its handled like a normal "client" connection (incomming) - * + * Adds an outgoing connection to the normal event notification system after it has been successfully established. + * + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. + + * @note + * after this call, its handled like a normal "client" connection (incomming) + * * @rturn success indicator */ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); @@ -129,24 +129,24 @@ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); /** * Marks a connection to be monitored for writable. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * * @note: - * the connection must be already added (as client or listener) - * + * the connection must be already added (as client or listener) + * * * @return sucess indicator */ bool evdp_writable_add(int32 fd, EVDP_DATA *ep); -/** +/** * Removes the connection from writable notification monitoring * - * @param fd connection identifier - * @param *ep event data pointr for the connection + * @param fd connection identifier + * @param *ep event data pointr for the connection * - */ + */ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); /** @@ -157,11 +157,11 @@ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); * * * @note: - * this will also clear the given EVENT_DATA block - * so the connection slot is in an "initial" blank status / ready to get reused. + * this will also clear the given EVENT_DATA block + * so the connection slot is in an "initial" blank status / ready to get reused. * */ -void evdp_remove(int32 fd, EVDP_DATA *ep); +void evdp_remove(int32 fd, EVDP_DATA *ep); diff --git a/src/common/evdp_epoll.c b/src/common/evdp_epoll.c index 0357dfc66..9f7c3d8ea 100644 --- a/src/common/evdp_epoll.c +++ b/src/common/evdp_epoll.c @@ -1,5 +1,5 @@ // -// Event Dispatcher Abstraction for EPOLL +// Event Dispatcher Abstraction for EPOLL // // Author: Florian Wilkemeyer // @@ -23,210 +23,220 @@ #include "../common/evdp.h" -#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. +#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. static int epoll_fd = -1; -void evdp_init(){ - - epoll_fd = epoll_create( EPOLL_MAX_PER_CYCLE ); - if(epoll_fd == -1){ - ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno) ); - exit(1); - } - +void evdp_init() +{ + + epoll_fd = epoll_create(EPOLL_MAX_PER_CYCLE); + if (epoll_fd == -1) { + ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno)); + exit(1); + } + }//end: evdp_init() -void evdp_final(){ - - if(epoll_fd != -1){ - close(epoll_fd); - epoll_fd = -1; - } - +void evdp_final() +{ + + if (epoll_fd != -1) { + close(epoll_fd); + epoll_fd = -1; + } + }//end: evdp_final() -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks){ - struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; - register struct epoll_event *ev; - register int nfds, n; - - if(max_events > EPOLL_MAX_PER_CYCLE) - max_events = EPOLL_MAX_PER_CYCLE; - - nfds = epoll_wait( epoll_fd, l_events, max_events, timeout_ticks); - if(nfds == -1){ - // @TODO: check if core is in shutdown mode. if - ignroe error. - - ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); - exit(1); //.. - } - - // Loop thru all events and copy it to the local ra evdp_event.. struct. - for(n = 0; n < nfds; n++){ - ev = &l_events[n]; - - out_fds->fd = ev->data.fd; - out_fds->events = 0; // clear - - if(ev->events & EPOLLHUP) - out_fds->events |= EVDP_EVENT_HUP; - - if(ev->events & EPOLLIN) - out_fds->events |= EVDP_EVENT_IN; - - if(ev->events & EPOLLOUT) - out_fds->events |= EVDP_EVENT_OUT; - - out_fds++; - } - - return nfds; // 0 on timeout or > 0 .. +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks) +{ + struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; + register struct epoll_event *ev; + register int nfds, n; + + if (max_events > EPOLL_MAX_PER_CYCLE) + max_events = EPOLL_MAX_PER_CYCLE; + + nfds = epoll_wait(epoll_fd, l_events, max_events, timeout_ticks); + if (nfds == -1) { + // @TODO: check if core is in shutdown mode. if - ignroe error. + + ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); + exit(1); //.. + } + + // Loop thru all events and copy it to the local ra evdp_event.. struct. + for (n = 0; n < nfds; n++) { + ev = &l_events[n]; + + out_fds->fd = ev->data.fd; + out_fds->events = 0; // clear + + if (ev->events & EPOLLHUP) + out_fds->events |= EVDP_EVENT_HUP; + + if (ev->events & EPOLLIN) + out_fds->events |= EVDP_EVENT_IN; + + if (ev->events & EPOLLOUT) + out_fds->events |= EVDP_EVENT_OUT; + + out_fds++; + } + + return nfds; // 0 on timeout or > 0 .. }//end: evdp_wait() -void evdp_remove(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added == true){ - - if( epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - } - - ep->ev_data.events = 0; // clear struct. - ep->ev_data.data.fd = -1; // .. clear struct .. +void evdp_remove(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added == true) { + + if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + } + + ep->ev_data.events = 0; // clear struct. + ep->ev_data.data.fd = -1; // .. clear struct .. + + ep->ev_added = false; // not added! + } - ep->ev_added = false; // not added! - } - }//end: evdp_remove() -bool evdp_addlistener(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLET|EPOLLIN; - ep->ev_data.data.fd = fd; - - // No check here for 'added ?' - // listeners cannot be added twice. - // - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0 ){ - ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addlistener(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLET|EPOLLIN; + ep->ev_data.data.fd = fd; + + // No check here for 'added ?' + // listeners cannot be added twice. + // + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addlistener() -bool evdp_addclient(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - ep->ev_data.data.fd = fd; - - // No check for "added?" here, - // this function only gets called upon accpept. - // - - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addclient(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + ep->ev_data.data.fd = fd; + + // No check for "added?" here, + // this function only gets called upon accpept. + // + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addclient() -bool evdp_addconnecting(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; - ep->ev_data.data.fd = fd; - - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - } - - ep->ev_added = true; - - return true; +bool evdp_addconnecting(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; + ep->ev_data.data.fd = fd; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + } + + ep->ev_added = true; + + return true; }//end: evdp_addconnecting() -bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep){ - int32 saved_mask; - - if(ep->ev_added != true){ - // ! - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); - return false; - } - - saved_mask = ep->ev_data.events; - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ - ep->ev_data.events = saved_mask; // restore old mask. - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - return false; - } - - return true; +bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep) +{ + int32 saved_mask; + + if (ep->ev_added != true) { + // ! + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); + return false; + } + + saved_mask = ep->ev_data.events; + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ep->ev_data.events = saved_mask; // restore old mask. + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + return false; + } + + return true; }//end: evdp_outgoingconnection_established() -bool evdp_writable_add(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added != true){ - ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); - return false; - } - - if(! (ep->ev_data.events & EPOLLOUT) ){ // - - ep->ev_data.events |= EPOLLOUT; - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0 ){ - ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. - return false; - } - } - - return true; +bool evdp_writable_add(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added != true) { + ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); + return false; + } + + if (!(ep->ev_data.events & EPOLLOUT)) { // + + ep->ev_data.events |= EPOLLOUT; + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. + return false; + } + } + + return true; }//end: evdp_writable_add() -void evdp_writable_remove(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added != true){ - ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); - return; - } - - if( ep->ev_data.events & EPOLLOUT ){ - - ep->ev_data.events &= ~EPOLLOUT; - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. - return; - } - } - - return; +void evdp_writable_remove(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added != true) { + ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); + return; + } + + if (ep->ev_data.events & EPOLLOUT) { + + ep->ev_data.events &= ~EPOLLOUT; + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. + return; + } + } + + return; }//end: evdp_writable_remove() diff --git a/src/common/grfio.c b/src/common/grfio.c index 8f430cfb9..f86f9c1cb 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -16,18 +16,18 @@ #include //---------------------------- -// file entry table struct +// file entry table struct //---------------------------- typedef struct _FILELIST { - int srclen; // compressed size - int srclen_aligned; - int declen; // original size - int srcpos; // position of entry in grf - int next; // index of next filelist entry with same hash (-1: end of entry chain) - char type; - char fn[128-4*5]; // file name - char* fnd; // if the file was cloned, contains name of original file - char gentry; // read grf file select + int srclen; // compressed size + int srclen_aligned; + int declen; // original size + int srcpos; // position of entry in grf + int next; // index of next filelist entry with same hash (-1: end of entry chain) + char type; + char fn[128-4*5]; // file name + char *fnd; // if the file was cloned, contains name of original file + char gentry; // read grf file select } FILELIST; #define FILELIST_TYPE_FILE 0x01 // entry is a file @@ -45,34 +45,33 @@ typedef struct _FILELIST { // stores info about every loaded file -FILELIST* filelist = NULL; -int filelist_entrys = 0; -int filelist_maxentry = 0; +FILELIST *filelist = NULL; +int filelist_entrys = 0; +int filelist_maxentry = 0; // stores grf file names -char** gentry_table = NULL; -int gentry_entrys = 0; -int gentry_maxentry = 0; +char **gentry_table = NULL; +int gentry_entrys = 0; +int gentry_maxentry = 0; // the path to the data directory char data_dir[1024] = ""; // little endian char array to uint conversion -static unsigned int getlong(unsigned char* p) +static unsigned int getlong(unsigned char *p) { - return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); + return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); } -static void NibbleSwap(unsigned char* src, int len) +static void NibbleSwap(unsigned char *src, int len) { - while( len > 0 ) - { - *src = (*src >> 4) | (*src << 4); - ++src; - --len; - } + while (len > 0) { + *src = (*src >> 4) | (*src << 4); + ++src; + --len; + } } @@ -80,114 +79,142 @@ static void NibbleSwap(unsigned char* src, int len) /// NOTE: Operation is symmetric (calling it twice gives back the original input). static uint8_t grf_substitution(uint8_t in) { - uint8_t out; - - switch( in ) - { - case 0x00: out = 0x2B; break; - case 0x2B: out = 0x00; break; - case 0x6C: out = 0x80; break; - case 0x01: out = 0x68; break; - case 0x68: out = 0x01; break; - case 0x48: out = 0x77; break; - case 0x60: out = 0xFF; break; - case 0x77: out = 0x48; break; - case 0xB9: out = 0xC0; break; - case 0xC0: out = 0xB9; break; - case 0xFE: out = 0xEB; break; - case 0xEB: out = 0xFE; break; - case 0x80: out = 0x6C; break; - case 0xFF: out = 0x60; break; - default: out = in; break; - } - - return out; + uint8_t out; + + switch (in) { + case 0x00: + out = 0x2B; + break; + case 0x2B: + out = 0x00; + break; + case 0x6C: + out = 0x80; + break; + case 0x01: + out = 0x68; + break; + case 0x68: + out = 0x01; + break; + case 0x48: + out = 0x77; + break; + case 0x60: + out = 0xFF; + break; + case 0x77: + out = 0x48; + break; + case 0xB9: + out = 0xC0; + break; + case 0xC0: + out = 0xB9; + break; + case 0xFE: + out = 0xEB; + break; + case 0xEB: + out = 0xFE; + break; + case 0x80: + out = 0x6C; + break; + case 0xFF: + out = 0x60; + break; + default: + out = in; + break; + } + + return out; } /* this is not used anywhere, is it ok to delete? */ //static void grf_shuffle_enc(BIT64* src) { -// BIT64 out; +// BIT64 out; // -// out.b[0] = src->b[3]; -// out.b[1] = src->b[4]; -// out.b[2] = src->b[5]; -// out.b[3] = src->b[0]; -// out.b[4] = src->b[1]; -// out.b[5] = src->b[6]; -// out.b[6] = src->b[2]; -// out.b[7] = grf_substitution(src->b[7]); +// out.b[0] = src->b[3]; +// out.b[1] = src->b[4]; +// out.b[2] = src->b[5]; +// out.b[3] = src->b[0]; +// out.b[4] = src->b[1]; +// out.b[5] = src->b[6]; +// out.b[6] = src->b[2]; +// out.b[7] = grf_substitution(src->b[7]); // -// *src = out; +// *src = out; //} -static void grf_shuffle_dec(BIT64* src) +static void grf_shuffle_dec(BIT64 *src) { - BIT64 out; - - out.b[0] = src->b[3]; - out.b[1] = src->b[4]; - out.b[2] = src->b[6]; - out.b[3] = src->b[0]; - out.b[4] = src->b[1]; - out.b[5] = src->b[2]; - out.b[6] = src->b[5]; - out.b[7] = grf_substitution(src->b[7]); - - *src = out; + BIT64 out; + + out.b[0] = src->b[3]; + out.b[1] = src->b[4]; + out.b[2] = src->b[6]; + out.b[3] = src->b[0]; + out.b[4] = src->b[1]; + out.b[5] = src->b[2]; + out.b[6] = src->b[5]; + out.b[7] = grf_substitution(src->b[7]); + + *src = out; } -static void grf_decode_header(unsigned char* buf, size_t len) +static void grf_decode_header(unsigned char *buf, size_t len) { - BIT64* p = (BIT64*)buf; - size_t nblocks = len / sizeof(BIT64); - size_t i; + BIT64 *p = (BIT64 *)buf; + size_t nblocks = len / sizeof(BIT64); + size_t i; - // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) - des_decrypt_block(&p[i]); + // first 20 blocks are all des-encrypted + for (i = 0; i < 20 && i < nblocks; ++i) + des_decrypt_block(&p[i]); - // the rest is plaintext, done. + // the rest is plaintext, done. } -static void grf_decode_full(unsigned char* buf, size_t len, int cycle) +static void grf_decode_full(unsigned char *buf, size_t len, int cycle) { - BIT64* p = (BIT64*)buf; - size_t nblocks = len / sizeof(BIT64); - int dcycle, scycle; - size_t i, j; - - // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) - des_decrypt_block(&p[i]); - - // after that only one of every 'dcycle' blocks is des-encrypted - dcycle = cycle; - - // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) - scycle = 7; - - // so decrypt/de-shuffle periodically - j = -1; // 0, adjusted to fit the ++j step - for( i = 20; i < nblocks; ++i ) - { - if( i % dcycle == 0 ) - {// decrypt block - des_decrypt_block(&p[i]); - continue; - } - - ++j; - if( j % scycle == 0 && j != 0 ) - {// de-shuffle block - grf_shuffle_dec(&p[i]); - continue; - } - - // plaintext, do nothing. - } + BIT64 *p = (BIT64 *)buf; + size_t nblocks = len / sizeof(BIT64); + int dcycle, scycle; + size_t i, j; + + // first 20 blocks are all des-encrypted + for (i = 0; i < 20 && i < nblocks; ++i) + des_decrypt_block(&p[i]); + + // after that only one of every 'dcycle' blocks is des-encrypted + dcycle = cycle; + + // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) + scycle = 7; + + // so decrypt/de-shuffle periodically + j = -1; // 0, adjusted to fit the ++j step + for (i = 20; i < nblocks; ++i) { + if (i % dcycle == 0) { + // decrypt block + des_decrypt_block(&p[i]); + continue; + } + + ++j; + if (j % scycle == 0 && j != 0) { + // de-shuffle block + grf_shuffle_dec(&p[i]); + continue; + } + + // plaintext, do nothing. + } } @@ -196,38 +223,35 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle) /// @param len length of the data /// @param entry_type flags associated with the data /// @param entry_len true (unaligned) length of the data -static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len) +static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len) { - if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED ) - {// fully encrypted - int digits; - int cycle; - int i; - - // compute number of digits of the entry length - digits = 1; - for( i = 10; i <= entry_len; i *= 10 ) - ++digits; - - // choose size of gap between two encrypted blocks - // digits: 0 1 2 3 4 5 6 7 8 9 ... - // cycle: 1 1 1 4 5 14 15 22 23 24 ... - cycle = ( digits < 3 ) ? 1 - : ( digits < 5 ) ? digits + 1 - : ( digits < 7 ) ? digits + 9 - : digits + 15; - - grf_decode_full(buf, len, cycle); - } - else - if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER ) - {// header encrypted - grf_decode_header(buf, len); - } - else - {// plaintext - ; - } + if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) { + // fully encrypted + int digits; + int cycle; + int i; + + // compute number of digits of the entry length + digits = 1; + for (i = 10; i <= entry_len; i *= 10) + ++digits; + + // choose size of gap between two encrypted blocks + // digits: 0 1 2 3 4 5 6 7 8 9 ... + // cycle: 1 1 1 4 5 14 15 22 23 24 ... + cycle = (digits < 3) ? 1 + : (digits < 5) ? digits + 1 + : (digits < 7) ? digits + 9 + : digits + 15; + + grf_decode_full(buf, len, cycle); + } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) { + // header encrypted + grf_decode_header(buf, len); + } else { + // plaintext + ; + } } @@ -236,23 +260,23 @@ static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entr ******************************************************/ /// zlib crc32 -unsigned long grfio_crc32(const unsigned char* buf, unsigned int len) +unsigned long grfio_crc32(const unsigned char *buf, unsigned int len) { - return crc32(crc32(0L, Z_NULL, 0), buf, len); + return crc32(crc32(0L, Z_NULL, 0), buf, len); } /// zlib uncompress -int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) +int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) { - return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return uncompress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); } /// zlib compress -int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) +int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) { - return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return compress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); } @@ -265,94 +289,94 @@ int filelist_hash[256]; // initializes the table that holds the first elements of all hash chains static void hashinit(void) { - int i; - for (i = 0; i < 256; i++) - filelist_hash[i] = -1; + int i; + for (i = 0; i < 256; i++) + filelist_hash[i] = -1; } // hashes a filename string into a number from {0..255} -static int filehash(const char* fname) +static int filehash(const char *fname) { - unsigned int hash = 0; - while(*fname) { - hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); - fname++; - } - return hash & 255; + unsigned int hash = 0; + while (*fname) { + hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); + fname++; + } + return hash & 255; } // finds a FILELIST entry with the specified file name -static FILELIST* filelist_find(const char* fname) +static FILELIST *filelist_find(const char *fname) { - int hash, index; + int hash, index; - if (!filelist) - return NULL; + if (!filelist) + return NULL; - hash = filelist_hash[filehash(fname)]; - for (index = hash; index != -1; index = filelist[index].next) - if(!strcmpi(filelist[index].fn, fname)) - break; + hash = filelist_hash[filehash(fname)]; + for (index = hash; index != -1; index = filelist[index].next) + if (!strcmpi(filelist[index].fn, fname)) + break; - return (index >= 0) ? &filelist[index] : NULL; + return (index >= 0) ? &filelist[index] : NULL; } // returns the original file name -char* grfio_find_file(const char* fname) +char *grfio_find_file(const char *fname) { - FILELIST *filelist = filelist_find(fname); - if (!filelist) return NULL; - return (!filelist->fnd ? filelist->fn : filelist->fnd); + FILELIST *filelist = filelist_find(fname); + if (!filelist) return NULL; + return (!filelist->fnd ? filelist->fn : filelist->fnd); } // adds a FILELIST entry into the list of loaded files -static FILELIST* filelist_add(FILELIST* entry) +static FILELIST *filelist_add(FILELIST *entry) { - int hash; + int hash; - #define FILELIST_ADDS 1024 // number increment of file lists ` +#define FILELIST_ADDS 1024 // number increment of file lists ` - if (filelist_entrys >= filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); - memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); - filelist_maxentry += FILELIST_ADDS; - } + if (filelist_entrys >= filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); + memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); + filelist_maxentry += FILELIST_ADDS; + } - memcpy (&filelist[filelist_entrys], entry, sizeof(FILELIST)); + memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST)); - hash = filehash(entry->fn); - filelist[filelist_entrys].next = filelist_hash[hash]; - filelist_hash[hash] = filelist_entrys; + hash = filehash(entry->fn); + filelist[filelist_entrys].next = filelist_hash[hash]; + filelist_hash[hash] = filelist_entrys; - filelist_entrys++; + filelist_entrys++; - return &filelist[filelist_entrys - 1]; + return &filelist[filelist_entrys - 1]; } // adds a new FILELIST entry or overwrites an existing one -static FILELIST* filelist_modify(FILELIST* entry) +static FILELIST *filelist_modify(FILELIST *entry) { - FILELIST* fentry = filelist_find(entry->fn); - if (fentry != NULL) { - int tmp = fentry->next; - memcpy(fentry, entry, sizeof(FILELIST)); - fentry->next = tmp; - } else { - fentry = filelist_add(entry); - } - return fentry; + FILELIST *fentry = filelist_find(entry->fn); + if (fentry != NULL) { + int tmp = fentry->next; + memcpy(fentry, entry, sizeof(FILELIST)); + fentry->next = tmp; + } else { + fentry = filelist_add(entry); + } + return fentry; } // shrinks the file list array if too long static void filelist_compact(void) { - if (filelist == NULL) - return; + if (filelist == NULL) + return; - if (filelist_entrys < filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); - filelist_maxentry = filelist_entrys; - } + if (filelist_entrys < filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); + filelist_maxentry = filelist_entrys; + } } @@ -362,457 +386,448 @@ static void filelist_compact(void) /// Combines are resource path with the data folder location to create local resource path. -static void grfio_localpath_create(char* buffer, size_t size, const char* filename) +static void grfio_localpath_create(char *buffer, size_t size, const char *filename) { - unsigned int i; - size_t len; - - len = strlen(data_dir); - - if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' ) - { - safesnprintf(buffer, size, "%s%s", data_dir, filename); - } - else - { - safesnprintf(buffer, size, "%s/%s", data_dir, filename); - } - - // normalize path - for( i = 0; buffer[i] != '\0'; ++i ) - if( buffer[i] == '\\' ) - buffer[i] = '/'; + unsigned int i; + size_t len; + + len = strlen(data_dir); + + if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\') { + safesnprintf(buffer, size, "%s%s", data_dir, filename); + } else { + safesnprintf(buffer, size, "%s/%s", data_dir, filename); + } + + // normalize path + for (i = 0; buffer[i] != '\0'; ++i) + if (buffer[i] == '\\') + buffer[i] = '/'; } /// Reads a file into a newly allocated buffer (from grf or data directory). -void* grfio_reads(const char* fname, int* size) +void *grfio_reads(const char *fname, int *size) { - unsigned char* buf2 = NULL; - - FILELIST* entry = filelist_find(fname); - if( entry == NULL || entry->gentry <= 0 ) {// LocalFileCheck - char lfname[256]; - int declen; - FILE* in; - grfio_localpath_create(lfname, sizeof(lfname), ( entry && entry->fnd ) ? entry->fnd : fname); - - in = fopen(lfname, "rb"); - if( in != NULL ) { - fseek(in,0,SEEK_END); - declen = ftell(in); - fseek(in,0,SEEK_SET); - buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination - if(fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); - fclose(in); - - if( size ) - *size = declen; - } else { - if (entry != NULL && entry->gentry < 0) { - entry->gentry = -entry->gentry; // local file checked - } else { - ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); - return NULL; - } - } - } - - if( entry != NULL && entry->gentry > 0 ) {// Archive[GRF] File Read - char* grfname = gentry_table[entry->gentry - 1]; - FILE* in = fopen(grfname, "rb"); - if( in != NULL ) { - int fsize = entry->srclen_aligned; - unsigned char *buf = (unsigned char *)aMalloc(fsize); - fseek(in, entry->srcpos, 0); - if(fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); - fclose(in); - - buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination - if( entry->type & FILELIST_TYPE_FILE ) - {// file - uLongf len; - grf_decode(buf, fsize, entry->type, entry->srclen); - len = entry->declen; - decode_zip(buf2, &len, buf, entry->srclen); - if (len != (uLong)entry->declen) { - ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); - aFree(buf); - aFree(buf2); - return NULL; - } - } else {// directory? - memcpy(buf2, buf, entry->declen); - } - - if( size ) - *size = entry->declen; - - aFree(buf); - } else { - ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); - return NULL; - } - } - - return buf2; + unsigned char *buf2 = NULL; + + FILELIST *entry = filelist_find(fname); + if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck + char lfname[256]; + int declen; + FILE *in; + grfio_localpath_create(lfname, sizeof(lfname), (entry && entry->fnd) ? entry->fnd : fname); + + in = fopen(lfname, "rb"); + if (in != NULL) { + fseek(in,0,SEEK_END); + declen = ftell(in); + fseek(in,0,SEEK_SET); + buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination + if (fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); + fclose(in); + + if (size) + *size = declen; + } else { + if (entry != NULL && entry->gentry < 0) { + entry->gentry = -entry->gentry; // local file checked + } else { + ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); + return NULL; + } + } + } + + if (entry != NULL && entry->gentry > 0) { // Archive[GRF] File Read + char *grfname = gentry_table[entry->gentry - 1]; + FILE *in = fopen(grfname, "rb"); + if (in != NULL) { + int fsize = entry->srclen_aligned; + unsigned char *buf = (unsigned char *)aMalloc(fsize); + fseek(in, entry->srcpos, 0); + if (fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); + fclose(in); + + buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination + if (entry->type & FILELIST_TYPE_FILE) { + // file + uLongf len; + grf_decode(buf, fsize, entry->type, entry->srclen); + len = entry->declen; + decode_zip(buf2, &len, buf, entry->srclen); + if (len != (uLong)entry->declen) { + ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); + aFree(buf); + aFree(buf2); + return NULL; + } + } else {// directory? + memcpy(buf2, buf, entry->declen); + } + + if (size) + *size = entry->declen; + + aFree(buf); + } else { + ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); + return NULL; + } + } + + return buf2; } /// Decodes encrypted filename from a version 01xx grf index. -static char* decode_filename(unsigned char* buf, int len) +static char *decode_filename(unsigned char *buf, int len) { - int lop; - for(lop=0;lop> 8; - - if( grf_version == 0x01 ) {// ****** Grf version 01xx ****** - list_size = grf_size - ftell(fp); - grf_filelist = (unsigned char *) aMalloc(list_size); - if(fread(grf_filelist,1,list_size,fp) != list_size) { ShowError("Couldn't read all grf_filelist element of %s \n", grfname); } - fclose(fp); - - entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; - - // Get an entry - for( entry = 0, ofs = 0; entry < entrys; ++entry ) { - FILELIST aentry; - - int ofs2 = ofs+getlong(grf_filelist+ofs)+4; - unsigned char type = grf_filelist[ofs2+12]; - if( type & FILELIST_TYPE_FILE ) { - char* fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); - int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; - - if( strlen(fname) > sizeof(aentry.fn) - 1 ) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - type |= ( isFullEncrypt(fname) ) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; - - aentry.srclen = srclen; - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + long grf_size,list_size; + unsigned char grf_header[0x2e]; + int entry,entrys,ofs,grf_version; + unsigned char *grf_filelist; + + FILE *fp = fopen(grfname, "rb"); + if (fp == NULL) { + ShowWarning("GRF data file not found: '%s'\n",grfname); + return 1; // 1:not found error + } else + ShowInfo("GRF data file found: '%s'\n",grfname); + + fseek(fp,0,SEEK_END); + grf_size = ftell(fp); + fseek(fp,0,SEEK_SET); + + if (fread(grf_header,1,0x2e,fp) != 0x2e) { + ShowError("Couldn't read all grf_header element of %s \n", grfname); + } + if (strcmp((const char *)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0) { + fclose(fp); + ShowError("GRF %s read error\n", grfname); + return 2; // 2:file format error + } + + grf_version = getlong(grf_header+0x2a) >> 8; + + if (grf_version == 0x01) { // ****** Grf version 01xx ****** + list_size = grf_size - ftell(fp); + grf_filelist = (unsigned char *) aMalloc(list_size); + if (fread(grf_filelist,1,list_size,fp) != list_size) { + ShowError("Couldn't read all grf_filelist element of %s \n", grfname); + } + fclose(fp); + + entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; + + // Get an entry + for (entry = 0, ofs = 0; entry < entrys; ++entry) { + FILELIST aentry; + + int ofs2 = ofs+getlong(grf_filelist+ofs)+4; + unsigned char type = grf_filelist[ofs2+12]; + if (type & FILELIST_TYPE_FILE) { + char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); + int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; + + if (strlen(fname) > sizeof(aentry.fn) - 1) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + type |= (isFullEncrypt(fname)) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; + + aentry.srclen = srclen; + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } - - ofs = ofs2 + 17; - } - - aFree(grf_filelist); - } else if( grf_version == 0x02 ) {// ****** Grf version 02xx ****** - unsigned char eheader[8]; - unsigned char *rBuf; - uLongf rSize, eSize; - - if(fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); - rSize = getlong(eheader); // Read Size - eSize = getlong(eheader+4); // Extend Size - - if( (long)rSize > grf_size-ftell(fp) ) { - fclose(fp); - ShowError("Illegal data format: GRF compress entry size\n"); - return 4; - } - - rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size - grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size - if(fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); - fclose(fp); - decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function - aFree(rBuf); - - entrys = getlong(grf_header+0x26) - 7; - - // Get an entry - for( entry = 0, ofs = 0; entry < entrys; ++entry ) { - FILELIST aentry; - - char* fname = (char*)(grf_filelist+ofs); - int ofs2 = ofs + (int)strlen(fname)+1; - int type = grf_filelist[ofs2+12]; - - if( strlen(fname) > sizeof(aentry.fn)-1 ) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - if( type & FILELIST_TYPE_FILE ) {// file - aentry.srclen = getlong(grf_filelist+ofs2+0); - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + filelist_modify(&aentry); + } + + ofs = ofs2 + 17; + } + + aFree(grf_filelist); + } else if (grf_version == 0x02) { // ****** Grf version 02xx ****** + unsigned char eheader[8]; + unsigned char *rBuf; + uLongf rSize, eSize; + + if (fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); + rSize = getlong(eheader); // Read Size + eSize = getlong(eheader+4); // Extend Size + + if ((long)rSize > grf_size-ftell(fp)) { + fclose(fp); + ShowError("Illegal data format: GRF compress entry size\n"); + return 4; + } + + rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size + grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size + if (fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); + fclose(fp); + decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function + aFree(rBuf); + + entrys = getlong(grf_header+0x26) - 7; + + // Get an entry + for (entry = 0, ofs = 0; entry < entrys; ++entry) { + FILELIST aentry; + + char *fname = (char *)(grf_filelist+ofs); + int ofs2 = ofs + (int)strlen(fname)+1; + int type = grf_filelist[ofs2+12]; + + if (strlen(fname) > sizeof(aentry.fn)-1) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + if (type & FILELIST_TYPE_FILE) { // file + aentry.srclen = getlong(grf_filelist+ofs2+0); + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } + filelist_modify(&aentry); + } - ofs = ofs2 + 17; - } + ofs = ofs2 + 17; + } - aFree(grf_filelist); - } else {// ****** Grf Other version ****** - fclose(fp); - ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); - return 4; - } + aFree(grf_filelist); + } else {// ****** Grf Other version ****** + fclose(fp); + ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); + return 4; + } - filelist_compact(); // Unnecessary area release of filelist + filelist_compact(); // Unnecessary area release of filelist - return 0; // 0:no error + return 0; // 0:no error } -static bool grfio_parse_restable_row(const char* row) +static bool grfio_parse_restable_row(const char *row) { - char w1[256], w2[256]; - char src[256], dst[256]; - char local[256]; - FILELIST* entry; - - if( sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2 ) - return false; - - if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL ) - return false; // we only need the maps' GAT and RSW files - - sprintf(src, "data\\%s", w1); - sprintf(dst, "data\\%s", w2); - - entry = filelist_find(dst); - if( entry != NULL ) - {// alias for GRF resource - FILELIST fentry; - memcpy(&fentry, entry, sizeof(FILELIST)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - grfio_localpath_create(local, sizeof(local), dst); - if( exists(local) ) - {// alias for local resource - FILELIST fentry; - memset(&fentry, 0, sizeof(fentry)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - return false; + char w1[256], w2[256]; + char src[256], dst[256]; + char local[256]; + FILELIST *entry; + + if (sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2) + return false; + + if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL) + return false; // we only need the maps' GAT and RSW files + + sprintf(src, "data\\%s", w1); + sprintf(dst, "data\\%s", w2); + + entry = filelist_find(dst); + if (entry != NULL) { + // alias for GRF resource + FILELIST fentry; + memcpy(&fentry, entry, sizeof(FILELIST)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + grfio_localpath_create(local, sizeof(local), dst); + if (exists(local)) { + // alias for local resource + FILELIST fentry; + memset(&fentry, 0, sizeof(fentry)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + return false; } /// Grfio Resource file check. static void grfio_resourcecheck(void) { - char restable[256]; - char *ptr, *buf; - int size; - FILE* fp; - int i = 0; - - // read resnametable from data directory and return if successful - grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); - - fp = fopen(restable, "rb"); - if( fp != NULL ) - { - char line[256]; - while( fgets(line, sizeof(line), fp) ) - { - if( grfio_parse_restable_row(line) ) - ++i; - } - - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); - return; // we're done here! - } - - // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory - buf = (char *)grfio_reads("data\\resnametable.txt", &size); - if( buf != NULL ) - { - buf[size] = '\0'; - - ptr = buf; - while( ptr - buf < size ) - { - if( grfio_parse_restable_row(ptr) ) - ++i; - - ptr = strchr(ptr, '\n'); - if( ptr == NULL ) break; - ptr++; - } - - aFree(buf); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); - return; - } + char restable[256]; + char *ptr, *buf; + int size; + FILE *fp; + int i = 0; + + // read resnametable from data directory and return if successful + grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); + + fp = fopen(restable, "rb"); + if (fp != NULL) { + char line[256]; + while (fgets(line, sizeof(line), fp)) { + if (grfio_parse_restable_row(line)) + ++i; + } + + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); + return; // we're done here! + } + + // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory + buf = (char *)grfio_reads("data\\resnametable.txt", &size); + if (buf != NULL) { + buf[size] = '\0'; + + ptr = buf; + while (ptr - buf < size) { + if (grfio_parse_restable_row(ptr)) + ++i; + + ptr = strchr(ptr, '\n'); + if (ptr == NULL) break; + ptr++; + } + + aFree(buf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); + return; + } } /// Reads a grf file and adds it to the list. -static int grfio_add(const char* fname) +static int grfio_add(const char *fname) { - if( gentry_entrys >= gentry_maxentry ) - { - #define GENTRY_ADDS 4 // The number increment of gentry_table entries - gentry_maxentry += GENTRY_ADDS; - gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); - memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS); - } + if (gentry_entrys >= gentry_maxentry) { +#define GENTRY_ADDS 4 // The number increment of gentry_table entries + gentry_maxentry += GENTRY_ADDS; + gentry_table = (char **)aRealloc(gentry_table, gentry_maxentry * sizeof(char *)); + memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char *) * GENTRY_ADDS); + } - gentry_table[gentry_entrys++] = aStrdup(fname); + gentry_table[gentry_entrys++] = aStrdup(fname); - return grfio_entryread(fname, gentry_entrys - 1); + return grfio_entryread(fname, gentry_entrys - 1); } /// Finalizes grfio. void grfio_final(void) { - if (filelist != NULL) { - int i; - for (i = 0; i < filelist_entrys; i++) - if (filelist[i].fnd != NULL) - aFree(filelist[i].fnd); - - aFree(filelist); - filelist = NULL; - } - filelist_entrys = filelist_maxentry = 0; - - if (gentry_table != NULL) { - int i; - for (i = 0; i < gentry_entrys; i++) - if (gentry_table[i] != NULL) - aFree(gentry_table[i]); - - aFree(gentry_table); - gentry_table = NULL; - } - gentry_entrys = gentry_maxentry = 0; + if (filelist != NULL) { + int i; + for (i = 0; i < filelist_entrys; i++) + if (filelist[i].fnd != NULL) + aFree(filelist[i].fnd); + + aFree(filelist); + filelist = NULL; + } + filelist_entrys = filelist_maxentry = 0; + + if (gentry_table != NULL) { + int i; + for (i = 0; i < gentry_entrys; i++) + if (gentry_table[i] != NULL) + aFree(gentry_table[i]); + + aFree(gentry_table); + gentry_table = NULL; + } + gentry_entrys = gentry_maxentry = 0; } /// Initializes grfio. -void grfio_init(const char* fname) +void grfio_init(const char *fname) { - FILE* data_conf; - int grf_num = 0; - - hashinit(); // hash table initialization - - data_conf = fopen(fname, "r"); - if( data_conf != NULL ) - { - char line[1024]; - while( fgets(line, sizeof(line), data_conf) ) - { - char w1[1024], w2[1024]; - - if( line[0] == '/' && line[1] == '/' ) - continue; // skip comments - - if( sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2 ) - continue; // skip unrecognized lines - - // Entry table reading - if( strcmp(w1, "grf") == 0 ) // GRF file - { - if( grfio_add(w2) == 0 ) - ++grf_num; - } - else if( strcmp(w1,"data_dir") == 0 ) // Data directory - { - safestrncpy(data_dir, w2, sizeof(data_dir)); - } - } - - fclose(data_conf); - ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); - } - - if( grf_num == 0 ) - ShowInfo("No GRF loaded, using default data directory\n"); - - // Unneccessary area release of filelist - filelist_compact(); - - // Resource check - grfio_resourcecheck(); + FILE *data_conf; + int grf_num = 0; + + hashinit(); // hash table initialization + + data_conf = fopen(fname, "r"); + if (data_conf != NULL) { + char line[1024]; + while (fgets(line, sizeof(line), data_conf)) { + char w1[1024], w2[1024]; + + if (line[0] == '/' && line[1] == '/') + continue; // skip comments + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; // skip unrecognized lines + + // Entry table reading + if (strcmp(w1, "grf") == 0) { // GRF file + if (grfio_add(w2) == 0) + ++grf_num; + } else if (strcmp(w1,"data_dir") == 0) { // Data directory + safestrncpy(data_dir, w2, sizeof(data_dir)); + } + } + + fclose(data_conf); + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); + } + + if (grf_num == 0) + ShowInfo("No GRF loaded, using default data directory\n"); + + // Unneccessary area release of filelist + filelist_compact(); + + // Resource check + grfio_resourcecheck(); } diff --git a/src/common/grfio.h b/src/common/grfio.h index c5a56a14e..ae2fbd67c 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -1,17 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _GRFIO_H_ -#define _GRFIO_H_ +#ifndef _GRFIO_H_ +#define _GRFIO_H_ -void grfio_init(const char* fname); +void grfio_init(const char *fname); void grfio_final(void); -void* grfio_reads(const char* fname, int* size); -char* grfio_find_file(const char* fname); +void *grfio_reads(const char *fname, int *size); +char *grfio_find_file(const char *fname); #define grfio_read(fn) grfio_reads(fn, NULL) unsigned long grfio_crc32(const unsigned char *buf, unsigned int len); -int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); -int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); +int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); +int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); #endif /* _GRFIO_H_ */ diff --git a/src/common/malloc.c b/src/common/malloc.c index 9976a28d5..396ec33cb 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -14,109 +14,109 @@ #if defined(MEMWATCH) -# include -# include "memwatch.h" -# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) -# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) -# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) -# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) -# define FREE(p,file,line,func) mwFree((p),(file),(line)) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) -# define MEMORY_CHECK() CHECK() +# include +# include "memwatch.h" +# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) +# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) +# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) +# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) +# define FREE(p,file,line,func) mwFree((p),(file),(line)) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) +# define MEMORY_CHECK() CHECK() #elif defined(DMALLOC) -# include -# include -# include "dmalloc.h" -# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) -# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) -# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() dmalloc_memory_allocated() -# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) -# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() +# include +# include +# include "dmalloc.h" +# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) +# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) +# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() dmalloc_memory_allocated() +# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) +# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() #elif defined(GCOLLECT) -# include "gc.h" -# ifdef GC_ADD_CALLER -# define RETURN_ADDR 0, -# else -# define RETURN_ADDR -# endif -# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) -# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) -# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) -# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) -# define FREE(p,file,line,func) GC_debug_free(p) -# define MEMORY_USAGE() GC_get_heap_size() -# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) -# define MEMORY_CHECK() GC_gcollect() +# include "gc.h" +# ifdef GC_ADD_CALLER +# define RETURN_ADDR 0, +# else +# define RETURN_ADDR +# endif +# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) +# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) +# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) +# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) +# define FREE(p,file,line,func) GC_debug_free(p) +# define MEMORY_USAGE() GC_get_heap_size() +# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) +# define MEMORY_CHECK() GC_gcollect() #else -# define MALLOC(n,file,line,func) malloc(n) -# define CALLOC(m,n,file,line,func) calloc((m),(n)) -# define REALLOC(p,n,file,line,func) realloc((p),(n)) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) true -# define MEMORY_CHECK() +# define MALLOC(n,file,line,func) malloc(n) +# define CALLOC(m,n,file,line,func) calloc((m),(n)) +# define REALLOC(p,n,file,line,func) realloc((p),(n)) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) true +# define MEMORY_CHECK() #endif -void* aMalloc_(size_t size, const char *file, int line, const char *func) +void *aMalloc_(size_t size, const char *file, int line, const char *func) { - void *ret = MALLOC(size, file, line, func); - // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - - return ret; + void *ret = MALLOC(size, file, line, func); + // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + + return ret; } -void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) +void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) { - void *ret = CALLOC(num, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = CALLOC(num, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } -void* aRealloc_(void *p, size_t size, const char *file, int line, const char *func) +void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func) { - void *ret = REALLOC(p, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = REALLOC(p, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + return ret; } -char* aStrdup_(const char *p, const char *file, int line, const char *func) +char *aStrdup_(const char *p, const char *file, int line, const char *func) { - char *ret = STRDUP(p, file, line, func); - // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + char *ret = STRDUP(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } void aFree_(void *p, const char *file, int line, const char *func) { - // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); - if (p) - FREE(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); + if (p) + FREE(p, file, line, func); - p = NULL; + p = NULL; } @@ -146,405 +146,397 @@ void aFree_(void *p, const char *file, int line, const char *func) */ /* ブロックのアライメント */ -#define BLOCK_ALIGNMENT1 16 -#define BLOCK_ALIGNMENT2 64 +#define BLOCK_ALIGNMENT1 16 +#define BLOCK_ALIGNMENT2 64 /* ブロックに入るデータ量 */ -#define BLOCK_DATA_COUNT1 128 -#define BLOCK_DATA_COUNT2 608 +#define BLOCK_DATA_COUNT1 128 +#define BLOCK_DATA_COUNT2 608 /* ブロックの大きさ: 16*128 + 64*576 = 40KB */ -#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) -#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) -#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) +#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) +#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) +#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) /* 一度に確保するブロックの数。 */ -#define BLOCK_ALLOC 104 +#define BLOCK_ALLOC 104 /* ブロック */ struct block { - struct block* block_next; /* 次に確保した領域 */ - struct block* unfill_prev; /* 次の埋まっていない領域 */ - struct block* unfill_next; /* 次の埋まっていない領域 */ - unsigned short unit_size; /* ユニットの大きさ */ - unsigned short unit_hash; /* ユニットのハッシュ */ - unsigned short unit_count; /* ユニットの個数 */ - unsigned short unit_used; /* 使用ユニット数 */ - unsigned short unit_unfill; /* 未使用ユニットの場所 */ - unsigned short unit_maxused; /* 使用ユニットの最大値 */ - char data[ BLOCK_DATA_SIZE ]; + struct block *block_next; /* 次に確保した領域 */ + struct block *unfill_prev; /* 次の埋まっていない領域 */ + struct block *unfill_next; /* 次の埋まっていない領域 */ + unsigned short unit_size; /* ユニットの大きさ */ + unsigned short unit_hash; /* ユニットのハッシュ */ + unsigned short unit_count; /* ユニットの個数 */ + unsigned short unit_used; /* 使用ユニット数 */ + unsigned short unit_unfill; /* 未使用ユニットの場所 */ + unsigned short unit_maxused; /* 使用ユニットの最大値 */ + char data[ BLOCK_DATA_SIZE ]; }; struct unit_head { - struct block *block; - const char* file; - unsigned short line; - unsigned short size; - long checksum; + struct block *block; + const char *file; + unsigned short line; + unsigned short size; + long checksum; }; -static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; -static struct block* block_first, *block_last, block_head; +static struct block *hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; +static struct block *block_first, *block_last, block_head; /* メモリを使い回せない領域用のデータ */ struct unit_head_large { - size_t size; - struct unit_head_large* prev; - struct unit_head_large* next; - struct unit_head unit_head; + size_t size; + struct unit_head_large *prev; + struct unit_head_large *next; + struct unit_head unit_head; }; static struct unit_head_large *unit_head_large_first = NULL; -static struct block* block_malloc(unsigned short hash); -static void block_free(struct block* p); +static struct block *block_malloc(unsigned short hash); +static void block_free(struct block *p); static size_t memmgr_usage_bytes; #define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ])) #define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0) -static unsigned short size2hash( size_t size ) +static unsigned short size2hash(size_t size) { - if( size <= BLOCK_DATA_SIZE1 ) { - return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; - } else if( size <= BLOCK_DATA_SIZE ){ - return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 - + BLOCK_DATA_COUNT1; - } else { - return 0xffff; // ブロック長を超える場合は hash にしない - } + if (size <= BLOCK_DATA_SIZE1) { + return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; + } else if (size <= BLOCK_DATA_SIZE) { + return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 + + BLOCK_DATA_COUNT1; + } else { + return 0xffff; // ブロック長を超える場合は hash にしない + } } -static size_t hash2size( unsigned short hash ) +static size_t hash2size(unsigned short hash) { - if( hash <= BLOCK_DATA_COUNT1) { - return hash * BLOCK_ALIGNMENT1; - } else { - return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; - } + if (hash <= BLOCK_DATA_COUNT1) { + return hash * BLOCK_ALIGNMENT1; + } else { + return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; + } } -void* _mmalloc(size_t size, const char *file, int line, const char *func ) +void *_mmalloc(size_t size, const char *file, int line, const char *func) { - struct block *block; - short size_hash = size2hash( size ); - struct unit_head *head; - - if (((long) size) < 0) { - ShowError("_mmalloc: %d\n", size); - return NULL; - } - - if(size == 0) { - return NULL; - } - memmgr_usage_bytes += size; - - /* ブロック長を超える領域の確保には、malloc() を用いる */ - /* その際、unit_head.block に NULL を代入して区別する */ - if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { - struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); - if(p != NULL) { - p->size = size; - p->unit_head.block = NULL; - p->unit_head.size = 0; - p->unit_head.file = file; - p->unit_head.line = line; - p->prev = NULL; - if (unit_head_large_first == NULL) - p->next = NULL; - else { - unit_head_large_first->prev = p; - p->next = unit_head_large_first; - } - unit_head_large_first = p; - *(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)p + sizeof(struct unit_head_large) - sizeof(long); - } else { - ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); - exit(EXIT_FAILURE); - } - } - - /* 同一サイズのブロックが確保されていない時、新たに確保する */ - if(hash_unfill[size_hash]) { - block = hash_unfill[size_hash]; - } else { - block = block_malloc(size_hash); - } - - if( block->unit_unfill == 0xFFFF ) { - // free済み領域が残っていない - memmgr_assert(block->unit_used < block->unit_count); - memmgr_assert(block->unit_used == block->unit_maxused); - head = block2unit(block, block->unit_maxused); - block->unit_used++; - block->unit_maxused++; - } else { - head = block2unit(block, block->unit_unfill); - block->unit_unfill = head->size; - block->unit_used++; - } - - if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { - // ユニットを使い果たしたので、unfillリストから削除 - if( block->unfill_prev == &block_head) { - hash_unfill[ size_hash ] = block->unfill_next; - } else { - block->unfill_prev->unfill_next = block->unfill_next; - } - if( block->unfill_next ) { - block->unfill_next->unfill_prev = block->unfill_prev; - } - block->unfill_prev = NULL; - } + struct block *block; + short size_hash = size2hash(size); + struct unit_head *head; + + if (((long) size) < 0) { + ShowError("_mmalloc: %d\n", size); + return NULL; + } + + if (size == 0) { + return NULL; + } + memmgr_usage_bytes += size; + + /* ブロック長を超える領域の確保には、malloc() を用いる */ + /* その際、unit_head.block に NULL を代入して区別する */ + if (hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { + struct unit_head_large *p = (struct unit_head_large *)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); + if (p != NULL) { + p->size = size; + p->unit_head.block = NULL; + p->unit_head.size = 0; + p->unit_head.file = file; + p->unit_head.line = line; + p->prev = NULL; + if (unit_head_large_first == NULL) + p->next = NULL; + else { + unit_head_large_first->prev = p; + p->next = unit_head_large_first; + } + unit_head_large_first = p; + *(long *)((char *)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)p + sizeof(struct unit_head_large) - sizeof(long); + } else { + ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); + exit(EXIT_FAILURE); + } + } + + /* 同一サイズのブロックが確保されていない時、新たに確保する */ + if (hash_unfill[size_hash]) { + block = hash_unfill[size_hash]; + } else { + block = block_malloc(size_hash); + } + + if (block->unit_unfill == 0xFFFF) { + // free済み領域が残っていない + memmgr_assert(block->unit_used < block->unit_count); + memmgr_assert(block->unit_used == block->unit_maxused); + head = block2unit(block, block->unit_maxused); + block->unit_used++; + block->unit_maxused++; + } else { + head = block2unit(block, block->unit_unfill); + block->unit_unfill = head->size; + block->unit_used++; + } + + if (block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { + // ユニットを使い果たしたので、unfillリストから削除 + if (block->unfill_prev == &block_head) { + hash_unfill[ size_hash ] = block->unfill_next; + } else { + block->unfill_prev->unfill_next = block->unfill_next; + } + if (block->unfill_next) { + block->unfill_next->unfill_prev = block->unfill_prev; + } + block->unfill_prev = NULL; + } #ifdef DEBUG_MEMMGR - { - size_t i, sz = hash2size( size_hash ); - for( i=0; iline != 0xfdfd ) - { - ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); - } - else - { - ShowError("Memory manager: not-allocated-data is changed.\n"); - } - break; - } - } - memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz ); - } + { + size_t i, sz = hash2size(size_hash); + for (i=0; iline != 0xfdfd) { + ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); + } else { + ShowError("Memory manager: not-allocated-data is changed.\n"); + } + break; + } + } + memset((char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz); + } #endif - head->block = block; - head->file = file; - head->line = line; - head->size = (unsigned short)size; - *(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)head + sizeof(struct unit_head) - sizeof(long); + head->block = block; + head->file = file; + head->line = line; + head->size = (unsigned short)size; + *(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)head + sizeof(struct unit_head) - sizeof(long); } -void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) +void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func) { - void *p = _mmalloc(num * size,file,line,func); - memset(p,0,num * size); - return p; + void *p = _mmalloc(num * size,file,line,func); + memset(p,0,num * size); + return p; } -void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func ) +void *_mrealloc(void *memblock, size_t size, const char *file, int line, const char *func) { - size_t old_size; - if(memblock == NULL) { - return _mmalloc(size,file,line,func); - } - - old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; - if( old_size == 0 ) { - old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; - } - if(old_size > size) { - // サイズ縮小 -> そのまま返す(手抜き) - return memblock; - } else { - // サイズ拡大 - void *p = _mmalloc(size,file,line,func); - if(p != NULL) { - memcpy(p,memblock,old_size); - } - _mfree(memblock,file,line,func); - return p; - } + size_t old_size; + if (memblock == NULL) { + return _mmalloc(size,file,line,func); + } + + old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; + if (old_size == 0) { + old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; + } + if (old_size > size) { + // サイズ縮小 -> そのまま返す(手抜き) + return memblock; + } else { + // サイズ拡大 + void *p = _mmalloc(size,file,line,func); + if (p != NULL) { + memcpy(p,memblock,old_size); + } + _mfree(memblock,file,line,func); + return p; + } } -char* _mstrdup(const char *p, const char *file, int line, const char *func ) +char *_mstrdup(const char *p, const char *file, int line, const char *func) { - if(p == NULL) { - return NULL; - } else { - size_t len = strlen(p); - char *string = (char *)_mmalloc(len + 1,file,line,func); - memcpy(string,p,len+1); - return string; - } + if (p == NULL) { + return NULL; + } else { + size_t len = strlen(p); + char *string = (char *)_mmalloc(len + 1,file,line,func); + memcpy(string,p,len+1); + return string; + } } -void _mfree(void *ptr, const char *file, int line, const char *func ) +void _mfree(void *ptr, const char *file, int line, const char *func) { - struct unit_head *head; - - if (ptr == NULL) - return; - - head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); - if(head->size == 0) { - /* malloc() で直に確保された領域 */ - struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); - if( - *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) - != 0xdeadbeaf) - { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - head->size = 0xFFFF; - if(head_large->prev) { - head_large->prev->next = head_large->next; - } else { - unit_head_large_first = head_large->next; - } - if(head_large->next) { - head_large->next->prev = head_large->prev; - } - memmgr_usage_bytes -= head_large->size; + struct unit_head *head; + + if (ptr == NULL) + return; + + head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); + if (head->size == 0) { + /* malloc() で直に確保された領域 */ + struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); + if ( + *(long *)((char *)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) + != 0xdeadbeaf) { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + head->size = 0xFFFF; + if (head_large->prev) { + head_large->prev->next = head_large->next; + } else { + unit_head_large_first = head_large->next; + } + if (head_large->next) { + head_large->next->prev = head_large->prev; + } + memmgr_usage_bytes -= head_large->size; #ifdef DEBUG_MEMMGR - // set freed memory to 0xfd - memset(ptr, 0xfd, head_large->size); + // set freed memory to 0xfd + memset(ptr, 0xfd, head_large->size); #endif - FREE(head_large,file,line,func); - } - } else { - /* ユニット解放 */ - struct block *block = head->block; - if( (char*)head - (char*)block > sizeof(struct block) ) { - ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); - } else if(head->block == NULL) { - ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); - } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - memmgr_usage_bytes -= head->size; - head->block = NULL; + FREE(head_large,file,line,func); + } + } else { + /* ユニット解放 */ + struct block *block = head->block; + if ((char *)head - (char *)block > sizeof(struct block)) { + ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); + } else if (head->block == NULL) { + ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); + } else if (*(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + memmgr_usage_bytes -= head->size; + head->block = NULL; #ifdef DEBUG_MEMMGR - memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) ); - head->file = file; - head->line = line; + memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long)); + head->file = file; + head->line = line; #endif - memmgr_assert( block->unit_used > 0 ); - if(--block->unit_used == 0) { - /* ブロックの解放 */ - block_free(block); - } else { - if( block->unfill_prev == NULL) { - // unfill リストに追加 - if( hash_unfill[ block->unit_hash ] ) { - hash_unfill[ block->unit_hash ]->unfill_prev = block; - } - block->unfill_prev = &block_head; - block->unfill_next = hash_unfill[ block->unit_hash ]; - hash_unfill[ block->unit_hash ] = block; - } - head->size = block->unit_unfill; - block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); - } - } - } + memmgr_assert(block->unit_used > 0); + if (--block->unit_used == 0) { + /* ブロックの解放 */ + block_free(block); + } else { + if (block->unfill_prev == NULL) { + // unfill リストに追加 + if (hash_unfill[ block->unit_hash ]) { + hash_unfill[ block->unit_hash ]->unfill_prev = block; + } + block->unfill_prev = &block_head; + block->unfill_next = hash_unfill[ block->unit_hash ]; + hash_unfill[ block->unit_hash ] = block; + } + head->size = block->unit_unfill; + block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); + } + } + } } /* ブロックを確保する */ -static struct block* block_malloc(unsigned short hash) -{ - int i; - struct block *p; - if(hash_unfill[0] != NULL) { - /* ブロック用の領域は確保済み */ - p = hash_unfill[0]; - hash_unfill[0] = hash_unfill[0]->unfill_next; - } else { - /* ブロック用の領域を新たに確保する */ - p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); - if(p == NULL) { - ShowFatalError("Memory manager::block_alloc failed.\n"); - exit(EXIT_FAILURE); - } - - if(block_first == NULL) { - /* 初回確保 */ - block_first = p; - } else { - block_last->block_next = p; - } - block_last = &p[BLOCK_ALLOC - 1]; - block_last->block_next = NULL; - /* ブロックを連結させる */ - for(i=0;iunfill_prev = &block_head; - p->unfill_next = NULL; - p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head)); - p->unit_hash = hash; - p->unit_count = BLOCK_DATA_SIZE / p->unit_size; - p->unit_used = 0; - p->unit_unfill = 0xFFFF; - p->unit_maxused = 0; +static struct block *block_malloc(unsigned short hash) { + int i; + struct block *p; + if (hash_unfill[0] != NULL) { + /* ブロック用の領域は確保済み */ + p = hash_unfill[0]; + hash_unfill[0] = hash_unfill[0]->unfill_next; + } else { + /* ブロック用の領域を新たに確保する */ + p = (struct block *)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__); + if (p == NULL) { + ShowFatalError("Memory manager::block_alloc failed.\n"); + exit(EXIT_FAILURE); + } + + if (block_first == NULL) { + /* 初回確保 */ + block_first = p; + } else { + block_last->block_next = p; + } + block_last = &p[BLOCK_ALLOC - 1]; + block_last->block_next = NULL; + /* ブロックを連結させる */ + for (i=0; iunfill_prev = &block_head; + p->unfill_next = NULL; + p->unit_size = (unsigned short)(hash2size(hash) + sizeof(struct unit_head)); + p->unit_hash = hash; + p->unit_count = BLOCK_DATA_SIZE / p->unit_size; + p->unit_used = 0; + p->unit_unfill = 0xFFFF; + p->unit_maxused = 0; #ifdef DEBUG_MEMMGR - memset( p->data, 0xfd, sizeof(p->data) ); + memset(p->data, 0xfd, sizeof(p->data)); #endif - return p; + return p; } -static void block_free(struct block* p) +static void block_free(struct block *p) { - if( p->unfill_prev ) { - if( p->unfill_prev == &block_head) { - hash_unfill[ p->unit_hash ] = p->unfill_next; - } else { - p->unfill_prev->unfill_next = p->unfill_next; - } - if( p->unfill_next ) { - p->unfill_next->unfill_prev = p->unfill_prev; - } - p->unfill_prev = NULL; - } - - p->unfill_next = hash_unfill[0]; - hash_unfill[0] = p; + if (p->unfill_prev) { + if (p->unfill_prev == &block_head) { + hash_unfill[ p->unit_hash ] = p->unfill_next; + } else { + p->unfill_prev->unfill_next = p->unfill_next; + } + if (p->unfill_next) { + p->unfill_next->unfill_prev = p->unfill_prev; + } + p->unfill_prev = NULL; + } + + p->unfill_next = hash_unfill[0]; + hash_unfill[0] = p; } -size_t memmgr_usage (void) +size_t memmgr_usage(void) { - return memmgr_usage_bytes / 1024; + return memmgr_usage_bytes / 1024; } #ifdef LOG_MEMMGR static char memmer_logfile[128]; static FILE *log_fp; -static void memmgr_log (char *buf) +static void memmgr_log(char *buf) { - if( !log_fp ) - { - time_t raw; - struct tm* t; - - log_fp = fopen(memmer_logfile,"at"); - if (!log_fp) log_fp = stdout; - - time(&raw); - t = localtime(&raw); - fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", - (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); - } - fprintf(log_fp, "%s", buf); - return; + if (!log_fp) { + time_t raw; + struct tm *t; + + log_fp = fopen(memmer_logfile,"at"); + if (!log_fp) log_fp = stdout; + + time(&raw); + t = localtime(&raw); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); + } + fprintf(log_fp, "%s", buf); + return; } #endif /* LOG_MEMMGR */ @@ -553,107 +545,105 @@ static void memmgr_log (char *buf) /// /// @param ptr Pointer to the memory /// @return true if the memory is active -bool memmgr_verify(void* ptr) +bool memmgr_verify(void *ptr) { - struct block* block = block_first; - struct unit_head_large* large = unit_head_large_first; - - if( ptr == NULL ) - return false;// never valid - - // search small blocks - while( block ) - { - if( (char*)ptr >= (char*)block && (char*)ptr < ((char*)block) + sizeof(struct block) ) - {// found memory block - if( block->unit_used && (char*)ptr >= block->data ) - {// memory block is being used and ptr points to a sub-unit - size_t i = (size_t)((char*)ptr - block->data)/block->unit_size; - struct unit_head* head = block2unit(block, i); - if( i < block->unit_maxused && head->block != NULL ) - {// memory unit is allocated, check if ptr points to the usable part - return ( (char*)ptr >= ((char*)head) + sizeof(struct unit_head) - sizeof(long) - && (char*)ptr < ((char*)head) + sizeof(struct unit_head) - sizeof(long) + head->size ); - } - } - return false; - } - block = block->block_next; - } - - // search large blocks - while( large ) - { - if( (char*)ptr >= (char*)large && (char*)ptr < ((char*)large) + large->size ) - {// found memory block, check if ptr points to the usable part - return ( (char*)ptr >= ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) - && (char*)ptr < ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size ); - } - large = large->next; - } - return false; + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; + + if (ptr == NULL) + return false;// never valid + + // search small blocks + while (block) { + if ((char *)ptr >= (char *)block && (char *)ptr < ((char *)block) + sizeof(struct block)) { + // found memory block + if (block->unit_used && (char *)ptr >= block->data) { + // memory block is being used and ptr points to a sub-unit + size_t i = (size_t)((char *)ptr - block->data)/block->unit_size; + struct unit_head *head = block2unit(block, i); + if (i < block->unit_maxused && head->block != NULL) { + // memory unit is allocated, check if ptr points to the usable part + return ((char *)ptr >= ((char *)head) + sizeof(struct unit_head) - sizeof(long) + && (char *)ptr < ((char *)head) + sizeof(struct unit_head) - sizeof(long) + head->size); + } + } + return false; + } + block = block->block_next; + } + + // search large blocks + while (large) { + if ((char *)ptr >= (char *)large && (char *)ptr < ((char *)large) + large->size) { + // found memory block, check if ptr points to the usable part + return ((char *)ptr >= ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) + && (char *)ptr < ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size); + } + large = large->next; + } + return false; } -static void memmgr_final (void) +static void memmgr_final(void) { - struct block *block = block_first; - struct unit_head_large *large = unit_head_large_first; + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; #ifdef LOG_MEMMGR - int count = 0; + int count = 0; #endif /* LOG_MEMMGR */ - while (block) { - if (block->unit_used) { - int i; - for (i = 0; i < block->unit_maxused; i++) { - struct unit_head *head = block2unit(block, i); - if(head->block != NULL) { - char* ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); + while (block) { + if (block->unit_used) { + int i; + for (i = 0; i < block->unit_maxused; i++) { + struct unit_head *head = block2unit(block, i); + if (head->block != NULL) { + char *ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); #ifdef LOG_MEMMGR - char buf[1024]; - sprintf (buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - head->file, head->line, (unsigned long)head->size, ptr); - memmgr_log (buf); + char buf[1024]; + sprintf(buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + head->file, head->line, (unsigned long)head->size, ptr); + memmgr_log(buf); #endif /* LOG_MEMMGR */ - // get block pointer and free it [celest] - _mfree(ptr, ALC_MARK); - } - } - } - block = block->block_next; - } - - while(large) { - struct unit_head_large *large2; + // get block pointer and free it [celest] + _mfree(ptr, ALC_MARK); + } + } + } + block = block->block_next; + } + + while (large) { + struct unit_head_large *large2; #ifdef LOG_MEMMGR - char buf[1024]; - sprintf (buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); - memmgr_log (buf); + char buf[1024]; + sprintf(buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); + memmgr_log(buf); #endif /* LOG_MEMMGR */ - large2 = large->next; - FREE(large,file,line,func); - large = large2; - } + large2 = large->next; + FREE(large,file,line,func); + large = large2; + } #ifdef LOG_MEMMGR - if(count == 0) { - ShowInfo("Memory manager: No memory leaks found.\n"); - } else { - ShowWarning("Memory manager: Memory leaks found and fixed.\n"); - fclose(log_fp); - } + if (count == 0) { + ShowInfo("Memory manager: No memory leaks found.\n"); + } else { + ShowWarning("Memory manager: Memory leaks found and fixed.\n"); + fclose(log_fp); + } #endif /* LOG_MEMMGR */ } -static void memmgr_init (void) +static void memmgr_init(void) { #ifdef LOG_MEMMGR - sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); - ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); - memset(hash_unfill, 0, sizeof(hash_unfill)); + sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); + ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); + memset(hash_unfill, 0, sizeof(hash_unfill)); #endif /* LOG_MEMMGR */ } #endif /* USE_MEMMGR */ @@ -668,51 +658,51 @@ static void memmgr_init (void) /// Tests the memory for errors and memory leaks. void malloc_memory_check(void) { - MEMORY_CHECK(); + MEMORY_CHECK(); } /// Returns true if a pointer is valid. /// The check is best-effort, false positives are possible. -bool malloc_verify_ptr(void* ptr) +bool malloc_verify_ptr(void *ptr) { #ifdef USE_MEMMGR - return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); + return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); #else - return MEMORY_VERIFY(ptr); + return MEMORY_VERIFY(ptr); #endif } -size_t malloc_usage (void) +size_t malloc_usage(void) { #ifdef USE_MEMMGR - return memmgr_usage (); + return memmgr_usage(); #else - return MEMORY_USAGE(); + return MEMORY_USAGE(); #endif } -void malloc_final (void) +void malloc_final(void) { #ifdef USE_MEMMGR - memmgr_final (); + memmgr_final(); #endif - MEMORY_CHECK(); + MEMORY_CHECK(); } -void malloc_init (void) +void malloc_init(void) { #if defined(DMALLOC) && defined(CYGWIN) - // http://dmalloc.com/docs/latest/online/dmalloc_19.html - dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); + // http://dmalloc.com/docs/latest/online/dmalloc_19.html + dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); #endif #ifdef GCOLLECT - // don't garbage collect, only report inaccessible memory that was not deallocated - GC_find_leak = 1; - GC_INIT(); + // don't garbage collect, only report inaccessible memory that was not deallocated + GC_find_leak = 1; + GC_INIT(); #endif #ifdef USE_MEMMGR - memmgr_init (); + memmgr_init(); #endif } diff --git a/src/common/malloc.h b/src/common/malloc.h index 6b4e8e5c4..58dcee6d7 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -33,31 +33,31 @@ #undef LOG_MEMMGR #endif -# define aMalloc(n) _mmalloc(n,ALC_MARK) -# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) -# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) -# define aStrdup(p) _mstrdup(p,ALC_MARK) -# define aFree(p) _mfree(p,ALC_MARK) - - void* _mmalloc (size_t size, const char *file, int line, const char *func); - void* _mcalloc (size_t num, size_t size, const char *file, int line, const char *func); - void* _mrealloc (void *p, size_t size, const char *file, int line, const char *func); - char* _mstrdup (const char *p, const char *file, int line, const char *func); - void _mfree (void *p, const char *file, int line, const char *func); +# define aMalloc(n) _mmalloc(n,ALC_MARK) +# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) +# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) +# define aStrdup(p) _mstrdup(p,ALC_MARK) +# define aFree(p) _mfree(p,ALC_MARK) + +void *_mmalloc(size_t size, const char *file, int line, const char *func); +void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func); +void *_mrealloc(void *p, size_t size, const char *file, int line, const char *func); +char *_mstrdup(const char *p, const char *file, int line, const char *func); +void _mfree(void *p, const char *file, int line, const char *func); #else -# define aMalloc(n) aMalloc_((n),ALC_MARK) -# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) -# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) -# define aStrdup(p) aStrdup_(p,ALC_MARK) -# define aFree(p) aFree_(p,ALC_MARK) +# define aMalloc(n) aMalloc_((n),ALC_MARK) +# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) +# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) +# define aStrdup(p) aStrdup_(p,ALC_MARK) +# define aFree(p) aFree_(p,ALC_MARK) - void* aMalloc_ (size_t size, const char *file, int line, const char *func); - void* aCalloc_ (size_t num, size_t size, const char *file, int line, const char *func); - void* aRealloc_ (void *p, size_t size, const char *file, int line, const char *func); - char* aStrdup_ (const char *p, const char *file, int line, const char *func); - void aFree_ (void *p, const char *file, int line, const char *func); +void *aMalloc_(size_t size, const char *file, int line, const char *func); +void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func); +void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func); +char *aStrdup_(const char *p, const char *file, int line, const char *func); +void aFree_(void *p, const char *file, int line, const char *func); #endif @@ -66,13 +66,13 @@ #ifdef __GNUC__ // GCC has variable length arrays - #define CREATE_BUFFER(name, type, size) type name[size] - #define DELETE_BUFFER(name) +#define CREATE_BUFFER(name, type, size) type name[size] +#define DELETE_BUFFER(name) #else // others don't, so we emulate them - #define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) - #define DELETE_BUFFER(name) aFree(name) +#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) +#define DELETE_BUFFER(name) aFree(name) #endif @@ -84,9 +84,9 @@ //////////////////////////////////////////////// void malloc_memory_check(void); -bool malloc_verify_ptr(void* ptr); -size_t malloc_usage (void); -void malloc_init (void); -void malloc_final (void); +bool malloc_verify_ptr(void *ptr); +size_t malloc_usage(void); +void malloc_init(void); +void malloc_final(void); #endif /* _MALLOC_H_ */ diff --git a/src/common/mapindex.c b/src/common/mapindex.c index d46047833..62d14590e 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -12,7 +12,7 @@ #include struct _indexes { - char name[MAP_NAME_LENGTH]; //Stores map name + char name[MAP_NAME_LENGTH]; //Stores map name } indexes[MAX_MAPINDEX]; int max_index = 0; @@ -23,161 +23,158 @@ char mapindex_cfgfile[80] = "db/map_index.txt"; /// Retrieves the map name from 'string' (removing .gat extension if present). /// Result gets placed either into 'buf' or in a static local buffer. -const char* mapindex_getmapname(const char* string, char* output) +const char *mapindex_getmapname(const char *string, char *output) { - static char buf[MAP_NAME_LENGTH]; - char* dest = (output != NULL) ? output : buf; - - size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); - if (len == MAP_NAME_LENGTH_EXT) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); - len--; - } - if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) - len -= 4; // strip .gat extension - - len = min(len, MAP_NAME_LENGTH-1); - strncpy(dest, string, len+1); - memset(&dest[len], '\0', MAP_NAME_LENGTH-len); - - return dest; + static char buf[MAP_NAME_LENGTH]; + char *dest = (output != NULL) ? output : buf; + + size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); + if (len == MAP_NAME_LENGTH_EXT) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); + len--; + } + if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) + len -= 4; // strip .gat extension + + len = min(len, MAP_NAME_LENGTH-1); + strncpy(dest, string, len+1); + memset(&dest[len], '\0', MAP_NAME_LENGTH-len); + + return dest; } /// Retrieves the map name from 'string' (adding .gat extension if not already present). /// Result gets placed either into 'buf' or in a static local buffer. -const char* mapindex_getmapname_ext(const char* string, char* output) +const char *mapindex_getmapname_ext(const char *string, char *output) { - static char buf[MAP_NAME_LENGTH_EXT]; - char* dest = (output != NULL) ? output : buf; + static char buf[MAP_NAME_LENGTH_EXT]; + char *dest = (output != NULL) ? output : buf; - size_t len; + size_t len; - strcpy(buf,string); - sscanf(string,"%*[^#]%*[#]%s",buf); + strcpy(buf,string); + sscanf(string,"%*[^#]%*[#]%s",buf); - len = safestrnlen(buf, MAP_NAME_LENGTH); + len = safestrnlen(buf, MAP_NAME_LENGTH); - if (len == MAP_NAME_LENGTH) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); - len--; - } - strncpy(dest, buf, len+1); + if (len == MAP_NAME_LENGTH) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); + len--; + } + strncpy(dest, buf, len+1); - if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { - strcpy(&dest[len], ".gat"); - len += 4; // add .gat extension - } + if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { + strcpy(&dest[len], ".gat"); + len += 4; // add .gat extension + } - memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); - - return dest; + memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); + + return dest; } /// Adds a map to the specified index /// Returns 1 if successful, 0 oherwise -int mapindex_addmap(int index, const char* name) +int mapindex_addmap(int index, const char *name) { - char map_name[MAP_NAME_LENGTH]; - - if (index == -1){ - for (index = 1; index < max_index; index++) - { - //if (strcmp(indexes[index].name,"#CLEARED#")==0) - if (indexes[index].name[0] == '\0') - break; - } - } - - if (index < 0 || index >= MAX_MAPINDEX) { - ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); - return 0; - } - - mapindex_getmapname(name, map_name); - - if (map_name[0] == '\0') { - ShowError("(mapindex_add) Cannot add maps with no name.\n"); - return 0; - } - - if (strlen(map_name) >= MAP_NAME_LENGTH) { - ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); - return 0; - } - - if (mapindex_exists(index)) - ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); - - safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); - if (max_index <= index) - max_index = index+1; - - return index; + char map_name[MAP_NAME_LENGTH]; + + if (index == -1) { + for (index = 1; index < max_index; index++) { + //if (strcmp(indexes[index].name,"#CLEARED#")==0) + if (indexes[index].name[0] == '\0') + break; + } + } + + if (index < 0 || index >= MAX_MAPINDEX) { + ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); + return 0; + } + + mapindex_getmapname(name, map_name); + + if (map_name[0] == '\0') { + ShowError("(mapindex_add) Cannot add maps with no name.\n"); + return 0; + } + + if (strlen(map_name) >= MAP_NAME_LENGTH) { + ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); + return 0; + } + + if (mapindex_exists(index)) + ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); + + safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); + if (max_index <= index) + max_index = index+1; + + return index; } -unsigned short mapindex_name2id(const char* name) +unsigned short mapindex_name2id(const char *name) { - //TODO: Perhaps use a db to speed this up? [Skotlex] - int i; - - char map_name[MAP_NAME_LENGTH]; - mapindex_getmapname(name, map_name); - - for (i = 1; i < max_index; i++) - { - if (strcmpi(indexes[i].name,map_name)==0) - return i; - } - ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); - return 0; + //TODO: Perhaps use a db to speed this up? [Skotlex] + int i; + + char map_name[MAP_NAME_LENGTH]; + mapindex_getmapname(name, map_name); + + for (i = 1; i < max_index; i++) { + if (strcmpi(indexes[i].name,map_name)==0) + return i; + } + ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); + return 0; } -const char* mapindex_id2name(unsigned short id) +const char *mapindex_id2name(unsigned short id) { - if (id > MAX_MAPINDEX || !mapindex_exists(id)) { - ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); - return indexes[0].name; // dummy empty string so that the callee doesn't crash - } - return indexes[id].name; + if (id > MAX_MAPINDEX || !mapindex_exists(id)) { + ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); + return indexes[0].name; // dummy empty string so that the callee doesn't crash + } + return indexes[id].name; } void mapindex_init(void) { - FILE *fp; - char line[1024]; - int last_index = -1; - int index; - char map_name[1024]; - - memset (&indexes, 0, sizeof (indexes)); - fp=fopen(mapindex_cfgfile,"r"); - if(fp==NULL){ - ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); - exit(EXIT_FAILURE); //Server can't really run without this file. - } - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - switch (sscanf(line, "%1023s\t%d", map_name, &index)) - { - case 1: //Map with no ID given, auto-assign - index = last_index+1; - case 2: //Map with ID given - mapindex_addmap(index,map_name); - break; - default: - continue; - } - last_index = index; - } - fclose(fp); + FILE *fp; + char line[1024]; + int last_index = -1; + int index; + char map_name[1024]; + + memset(&indexes, 0, sizeof(indexes)); + fp=fopen(mapindex_cfgfile,"r"); + if (fp==NULL) { + ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); + exit(EXIT_FAILURE); //Server can't really run without this file. + } + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + switch (sscanf(line, "%1023s\t%d", map_name, &index)) { + case 1: //Map with no ID given, auto-assign + index = last_index+1; + case 2: //Map with ID given + mapindex_addmap(index,map_name); + break; + default: + continue; + } + last_index = index; + } + fclose(fp); } -int mapindex_removemap(int index){ - indexes[index].name[0] = '\0'; - return 0; +int mapindex_removemap(int index) +{ + indexes[index].name[0] = '\0'; + return 0; } void mapindex_final(void) diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 75cb254c0..4889d20f1 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -47,14 +47,14 @@ extern char mapindex_cfgfile[80]; #define MAP_MALAYA "malaya" #define MAP_ECLAGE "eclage" -const char* mapindex_getmapname(const char* string, char* output); -const char* mapindex_getmapname_ext(const char* string, char* output); -unsigned short mapindex_name2id(const char*); -const char* mapindex_id2name(unsigned short); +const char *mapindex_getmapname(const char *string, char *output); +const char *mapindex_getmapname_ext(const char *string, char *output); +unsigned short mapindex_name2id(const char *); +const char *mapindex_id2name(unsigned short); void mapindex_init(void); void mapindex_final(void); -int mapindex_addmap(int index, const char* name); +int mapindex_addmap(int index, const char *name); int mapindex_removemap(int index); #endif /* _MAPINDEX_H_ */ diff --git a/src/common/md5calc.c b/src/common/md5calc.c index 05fde42cc..bd4b59ad0 100644 --- a/src/common/md5calc.c +++ b/src/common/md5calc.c @@ -21,22 +21,22 @@ static unsigned int *pX; // String Table static const unsigned int T[] = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 }; // ROTATE_LEFT The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC. @@ -45,196 +45,244 @@ static const unsigned int T[] = { // The function used for other calculation static unsigned int F(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Y) | (~X & Z); + return (X & Y) | (~X & Z); } static unsigned int G(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Z) | (Y & ~Z); + return (X & Z) | (Y & ~Z); } static unsigned int H(unsigned int X, unsigned int Y, unsigned int Z) { - return X ^ Y ^ Z; + return X ^ Y ^ Z; } static unsigned int I(unsigned int X, unsigned int Y, unsigned int Z) { - return Y ^ (X | ~Z); + return Y ^ (X | ~Z); } static unsigned int Round(unsigned int a, unsigned int b, unsigned int FGHI, - unsigned int k, unsigned int s, unsigned int i) + unsigned int k, unsigned int s, unsigned int i) { - return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); + return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); } static void Round1(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, F(b,c,d), k, s, i); + *a = Round(*a, b, F(b,c,d), k, s, i); } static void Round2(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, G(b,c,d), k, s, i); + *a = Round(*a, b, G(b,c,d), k, s, i); } static void Round3(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, H(b,c,d), k, s, i); + *a = Round(*a, b, H(b,c,d), k, s, i); } static void Round4(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, I(b,c,d), k, s, i); + *a = Round(*a, b, I(b,c,d), k, s, i); } static void MD5_Round_Calculate(const unsigned char *block, - unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) + unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) { - //create X It is since it is required. - unsigned int X[16]; //512bit 64byte - int j,k; - - //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) - unsigned int A=*A2, B=*B2, C=*C2, D=*D2; - unsigned int AA = A,BB = B,CC = C,DD = D; - - //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 - pX = X; - - //Copy block(padding_message) i into X - for (j=0,k=0; j<64; j+=4,k++) - X[k] = ( (unsigned int )block[j] ) // 8byte*4 -> 32byte conversion - | ( ((unsigned int )block[j+1]) << 8 ) // A function called Decode as used in the field of RFC - | ( ((unsigned int )block[j+2]) << 16 ) - | ( ((unsigned int )block[j+3]) << 24 ); - - - //Round 1 - Round1(&A,B,C,D, 0, 7, 0); Round1(&D,A,B,C, 1, 12, 1); Round1(&C,D,A,B, 2, 17, 2); Round1(&B,C,D,A, 3, 22, 3); - Round1(&A,B,C,D, 4, 7, 4); Round1(&D,A,B,C, 5, 12, 5); Round1(&C,D,A,B, 6, 17, 6); Round1(&B,C,D,A, 7, 22, 7); - Round1(&A,B,C,D, 8, 7, 8); Round1(&D,A,B,C, 9, 12, 9); Round1(&C,D,A,B, 10, 17, 10); Round1(&B,C,D,A, 11, 22, 11); - Round1(&A,B,C,D, 12, 7, 12); Round1(&D,A,B,C, 13, 12, 13); Round1(&C,D,A,B, 14, 17, 14); Round1(&B,C,D,A, 15, 22, 15); - - //Round 2 - Round2(&A,B,C,D, 1, 5, 16); Round2(&D,A,B,C, 6, 9, 17); Round2(&C,D,A,B, 11, 14, 18); Round2(&B,C,D,A, 0, 20, 19); - Round2(&A,B,C,D, 5, 5, 20); Round2(&D,A,B,C, 10, 9, 21); Round2(&C,D,A,B, 15, 14, 22); Round2(&B,C,D,A, 4, 20, 23); - Round2(&A,B,C,D, 9, 5, 24); Round2(&D,A,B,C, 14, 9, 25); Round2(&C,D,A,B, 3, 14, 26); Round2(&B,C,D,A, 8, 20, 27); - Round2(&A,B,C,D, 13, 5, 28); Round2(&D,A,B,C, 2, 9, 29); Round2(&C,D,A,B, 7, 14, 30); Round2(&B,C,D,A, 12, 20, 31); - - //Round 3 - Round3(&A,B,C,D, 5, 4, 32); Round3(&D,A,B,C, 8, 11, 33); Round3(&C,D,A,B, 11, 16, 34); Round3(&B,C,D,A, 14, 23, 35); - Round3(&A,B,C,D, 1, 4, 36); Round3(&D,A,B,C, 4, 11, 37); Round3(&C,D,A,B, 7, 16, 38); Round3(&B,C,D,A, 10, 23, 39); - Round3(&A,B,C,D, 13, 4, 40); Round3(&D,A,B,C, 0, 11, 41); Round3(&C,D,A,B, 3, 16, 42); Round3(&B,C,D,A, 6, 23, 43); - Round3(&A,B,C,D, 9, 4, 44); Round3(&D,A,B,C, 12, 11, 45); Round3(&C,D,A,B, 15, 16, 46); Round3(&B,C,D,A, 2, 23, 47); - - //Round 4 - Round4(&A,B,C,D, 0, 6, 48); Round4(&D,A,B,C, 7, 10, 49); Round4(&C,D,A,B, 14, 15, 50); Round4(&B,C,D,A, 5, 21, 51); - Round4(&A,B,C,D, 12, 6, 52); Round4(&D,A,B,C, 3, 10, 53); Round4(&C,D,A,B, 10, 15, 54); Round4(&B,C,D,A, 1, 21, 55); - Round4(&A,B,C,D, 8, 6, 56); Round4(&D,A,B,C, 15, 10, 57); Round4(&C,D,A,B, 6, 15, 58); Round4(&B,C,D,A, 13, 21, 59); - Round4(&A,B,C,D, 4, 6, 60); Round4(&D,A,B,C, 11, 10, 61); Round4(&C,D,A,B, 2, 15, 62); Round4(&B,C,D,A, 9, 21, 63); - - // Then perform the following additions. (let's add) - *A2 = A + AA; - *B2 = B + BB; - *C2 = C + CC; - *D2 = D + DD; - - //The clearance of confidential information - memset(pX, 0, sizeof(X)); + //create X It is since it is required. + unsigned int X[16]; //512bit 64byte + int j,k; + + //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) + unsigned int A=*A2, B=*B2, C=*C2, D=*D2; + unsigned int AA = A,BB = B,CC = C,DD = D; + + //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 + pX = X; + + //Copy block(padding_message) i into X + for (j=0,k=0; j<64; j+=4,k++) + X[k] = ((unsigned int)block[j]) // 8byte*4 -> 32byte conversion + | (((unsigned int)block[j+1]) << 8) // A function called Decode as used in the field of RFC + | (((unsigned int)block[j+2]) << 16) + | (((unsigned int)block[j+3]) << 24); + + + //Round 1 + Round1(&A,B,C,D, 0, 7, 0); + Round1(&D,A,B,C, 1, 12, 1); + Round1(&C,D,A,B, 2, 17, 2); + Round1(&B,C,D,A, 3, 22, 3); + Round1(&A,B,C,D, 4, 7, 4); + Round1(&D,A,B,C, 5, 12, 5); + Round1(&C,D,A,B, 6, 17, 6); + Round1(&B,C,D,A, 7, 22, 7); + Round1(&A,B,C,D, 8, 7, 8); + Round1(&D,A,B,C, 9, 12, 9); + Round1(&C,D,A,B, 10, 17, 10); + Round1(&B,C,D,A, 11, 22, 11); + Round1(&A,B,C,D, 12, 7, 12); + Round1(&D,A,B,C, 13, 12, 13); + Round1(&C,D,A,B, 14, 17, 14); + Round1(&B,C,D,A, 15, 22, 15); + + //Round 2 + Round2(&A,B,C,D, 1, 5, 16); + Round2(&D,A,B,C, 6, 9, 17); + Round2(&C,D,A,B, 11, 14, 18); + Round2(&B,C,D,A, 0, 20, 19); + Round2(&A,B,C,D, 5, 5, 20); + Round2(&D,A,B,C, 10, 9, 21); + Round2(&C,D,A,B, 15, 14, 22); + Round2(&B,C,D,A, 4, 20, 23); + Round2(&A,B,C,D, 9, 5, 24); + Round2(&D,A,B,C, 14, 9, 25); + Round2(&C,D,A,B, 3, 14, 26); + Round2(&B,C,D,A, 8, 20, 27); + Round2(&A,B,C,D, 13, 5, 28); + Round2(&D,A,B,C, 2, 9, 29); + Round2(&C,D,A,B, 7, 14, 30); + Round2(&B,C,D,A, 12, 20, 31); + + //Round 3 + Round3(&A,B,C,D, 5, 4, 32); + Round3(&D,A,B,C, 8, 11, 33); + Round3(&C,D,A,B, 11, 16, 34); + Round3(&B,C,D,A, 14, 23, 35); + Round3(&A,B,C,D, 1, 4, 36); + Round3(&D,A,B,C, 4, 11, 37); + Round3(&C,D,A,B, 7, 16, 38); + Round3(&B,C,D,A, 10, 23, 39); + Round3(&A,B,C,D, 13, 4, 40); + Round3(&D,A,B,C, 0, 11, 41); + Round3(&C,D,A,B, 3, 16, 42); + Round3(&B,C,D,A, 6, 23, 43); + Round3(&A,B,C,D, 9, 4, 44); + Round3(&D,A,B,C, 12, 11, 45); + Round3(&C,D,A,B, 15, 16, 46); + Round3(&B,C,D,A, 2, 23, 47); + + //Round 4 + Round4(&A,B,C,D, 0, 6, 48); + Round4(&D,A,B,C, 7, 10, 49); + Round4(&C,D,A,B, 14, 15, 50); + Round4(&B,C,D,A, 5, 21, 51); + Round4(&A,B,C,D, 12, 6, 52); + Round4(&D,A,B,C, 3, 10, 53); + Round4(&C,D,A,B, 10, 15, 54); + Round4(&B,C,D,A, 1, 21, 55); + Round4(&A,B,C,D, 8, 6, 56); + Round4(&D,A,B,C, 15, 10, 57); + Round4(&C,D,A,B, 6, 15, 58); + Round4(&B,C,D,A, 13, 21, 59); + Round4(&A,B,C,D, 4, 6, 60); + Round4(&D,A,B,C, 11, 10, 61); + Round4(&C,D,A,B, 2, 15, 62); + Round4(&B,C,D,A, 9, 21, 63); + + // Then perform the following additions. (let's add) + *A2 = A + AA; + *B2 = B + BB; + *C2 = C + CC; + *D2 = D + DD; + + //The clearance of confidential information + memset(pX, 0, sizeof(X)); } -static void MD5_String2binary(const char * string, unsigned char * output) +static void MD5_String2binary(const char *string, unsigned char *output) { -//var - /*8bit*/ - unsigned char padding_message[64]; //Extended message 512bit 64byte - unsigned char *pstring; //The position of string in the present scanning notes is held. - - /*32bit*/ - unsigned int string_byte_len, //The byte chief of string is held. - string_bit_len, //The bit length of string is held. - copy_len, //The number of bytes which is used by 1-3 and which remained - msg_digest[4]; //Message digest 128bit 4byte - unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) - *B = &msg_digest[1], - *C = &msg_digest[2], - *D = &msg_digest[3]; - int i; - -//prog - //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) - *A = 0x67452301; - *B = 0xefcdab89; - *C = 0x98badcfe; - *D = 0x10325476; - - //Step 1.Append Padding Bits (extension of a mark bit) - //1-1 - string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. - pstring = (unsigned char *)string; //The position of the present character sequence is set. - - //1-2 Repeat calculation until length becomes less than 64 bytes. - for (i=string_byte_len; 64<=i; i-=64,pstring+=64) + //var + /*8bit*/ + unsigned char padding_message[64]; //Extended message 512bit 64byte + unsigned char *pstring; //The position of string in the present scanning notes is held. + + /*32bit*/ + unsigned int string_byte_len, //The byte chief of string is held. + string_bit_len, //The bit length of string is held. + copy_len, //The number of bytes which is used by 1-3 and which remained + msg_digest[4]; //Message digest 128bit 4byte + unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) + *B = &msg_digest[1], + *C = &msg_digest[2], + *D = &msg_digest[3]; + int i; + + //prog + //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) + *A = 0x67452301; + *B = 0xefcdab89; + *C = 0x98badcfe; + *D = 0x10325476; + + //Step 1.Append Padding Bits (extension of a mark bit) + //1-1 + string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. + pstring = (unsigned char *)string; //The position of the present character sequence is set. + + //1-2 Repeat calculation until length becomes less than 64 bytes. + for (i=string_byte_len; 64<=i; i-=64,pstring+=64) MD5_Round_Calculate(pstring, A,B,C,D); - //1-3 - copy_len = string_byte_len % 64; //The number of bytes which remained is computed. - strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. - memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. - padding_message[copy_len] |= 0x80; //The next of a message is 1. - - //1-4 - //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. - if (56 <= copy_len) { - MD5_Round_Calculate(padding_message, A,B,C,D); - memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. - } - - //Step 2.Append Length (the information on length is added) - string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) - memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. - - //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. - if (UINT_MAX / 8 < string_byte_len) { - unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; - memcpy(&padding_message[60], &high, 4); - } else - memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. - - //Step 4.Process Message in 16-Word Blocks (calculation of MD5) - MD5_Round_Calculate(padding_message, A,B,C,D); - - //Step 5.Output (output) - memcpy(output,msg_digest,16); + //1-3 + copy_len = string_byte_len % 64; //The number of bytes which remained is computed. + strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. + memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. + padding_message[copy_len] |= 0x80; //The next of a message is 1. + + //1-4 + //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. + if (56 <= copy_len) { + MD5_Round_Calculate(padding_message, A,B,C,D); + memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. + } + + //Step 2.Append Length (the information on length is added) + string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) + memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. + + //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. + if (UINT_MAX / 8 < string_byte_len) { + unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; + memcpy(&padding_message[60], &high, 4); + } else + memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. + + //Step 4.Process Message in 16-Word Blocks (calculation of MD5) + MD5_Round_Calculate(padding_message, A,B,C,D); + + //Step 5.Output (output) + memcpy(output,msg_digest,16); } //------------------------------------------------------------------- // The function for the exteriors /** output is the coded binary in the character sequence which wants to code string. */ -void MD5_Binary(const char * string, unsigned char * output) +void MD5_Binary(const char *string, unsigned char *output) { - MD5_String2binary(string,output); + MD5_String2binary(string,output); } /** output is the coded character sequence in the character sequence which wants to code string. */ -void MD5_String(const char * string, char * output) +void MD5_String(const char *string, char *output) { - unsigned char digest[16]; - - MD5_String2binary(string,digest); - sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[ 0], digest[ 1], digest[ 2], digest[ 3], - digest[ 4], digest[ 5], digest[ 6], digest[ 7], - digest[ 8], digest[ 9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); + unsigned char digest[16]; + + MD5_String2binary(string,digest); + sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + digest[ 0], digest[ 1], digest[ 2], digest[ 3], + digest[ 4], digest[ 5], digest[ 6], digest[ 7], + digest[ 8], digest[ 9], digest[10], digest[11], + digest[12], digest[13], digest[14], digest[15]); } /** output is a sequence of non-zero characters to be used as password salt. */ -void MD5_Salt(unsigned int len, char * output) +void MD5_Salt(unsigned int len, char *output) { - unsigned int i; - for( i = 0; i < len; ++i ) - output[i] = (char)(1 + rnd() % 255); + unsigned int i; + for (i = 0; i < len; ++i) + output[i] = (char)(1 + rnd() % 255); } diff --git a/src/common/md5calc.h b/src/common/md5calc.h index 323affa2c..4a112a660 100644 --- a/src/common/md5calc.h +++ b/src/common/md5calc.h @@ -1,8 +1,8 @@ #ifndef _MD5CALC_H_ #define _MD5CALC_H_ -void MD5_String(const char * string, char * output); -void MD5_Binary(const char * string, unsigned char * output); -void MD5_Salt(unsigned int len, char * output); +void MD5_String(const char *string, char *output); +void MD5_Binary(const char *string, unsigned char *output); +void MD5_Salt(unsigned int len, char *output); #endif /* _MD5CALC_H_ */ diff --git a/src/common/mempool.c b/src/common/mempool.c index 35b03034d..62db7b9e3 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -30,9 +30,9 @@ #include "../common/malloc.h" #include "../common/mutex.h" -#define ALIGN16 ra_align(16) +#define ALIGN16 ra_align(16) #define ALIGN_TO(x, a) (x + ( a - ( x % a) ) ) -#define ALIGN_TO_16(x) ALIGN_TO(x, 16) +#define ALIGN_TO_16(x) ALIGN_TO(x, 16) #undef MEMPOOL_DEBUG #define MEMPOOLASSERT @@ -40,523 +40,532 @@ #define NODE_TO_DATA(x) ( ((char*)x) + sizeof(struct node) ) #define DATA_TO_NODE(x) ( (struct node*)(((char*)x) - sizeof(struct node)) ) -struct ra_align(16) node{ - void *next; - void *segment; +struct ra_align(16) node { + void *next; + void *segment; #ifdef MEMPOOLASSERT - bool used; - uint64 magic; - #define NODE_MAGIC 0xBEEF00EAEACAFE07ll + bool used; + uint64 magic; +#define NODE_MAGIC 0xBEEF00EAEACAFE07ll #endif }; // The Pointer to this struct is the base address of the segment itself. -struct pool_segment{ - mempool pool; // pool, this segment belongs to - struct pool_segment *next; - int64 num_nodes_total; - int64 num_bytes; +struct pool_segment { + mempool pool; // pool, this segment belongs to + struct pool_segment *next; + int64 num_nodes_total; + int64 num_bytes; }; -struct mempool{ - // Settings - char *name; - uint64 elem_size; - uint64 elem_realloc_step; - int64 elem_realloc_thresh; - - // Callbacks that get called for every node that gets allocated - // Example usage: initialization of mutex/lock for each node. - memPoolOnNodeAllocationProc onalloc; - memPoolOnNodeDeallocationProc ondealloc; - - // Locks - SPIN_LOCK segmentLock; - SPIN_LOCK nodeLock; - - - // Internal - struct pool_segment *segments; - struct node *free_list; - - volatile int64 num_nodes_total; - volatile int64 num_nodes_free; - - volatile int64 num_segments; - volatile int64 num_bytes_total; - - volatile int64 peak_nodes_used; // Peak Node Usage - volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) - - // list (used for global management such as allocator..) - struct mempool *next; +struct mempool { + // Settings + char *name; + uint64 elem_size; + uint64 elem_realloc_step; + int64 elem_realloc_thresh; + + // Callbacks that get called for every node that gets allocated + // Example usage: initialization of mutex/lock for each node. + memPoolOnNodeAllocationProc onalloc; + memPoolOnNodeDeallocationProc ondealloc; + + // Locks + SPIN_LOCK segmentLock; + SPIN_LOCK nodeLock; + + + // Internal + struct pool_segment *segments; + struct node *free_list; + + volatile int64 num_nodes_total; + volatile int64 num_nodes_free; + + volatile int64 num_segments; + volatile int64 num_bytes_total; + + volatile int64 peak_nodes_used; // Peak Node Usage + volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) + + // list (used for global management such as allocator..) + struct mempool *next; } ra_align(8); // Dont touch the alignment, otherwise interlocked functions are broken .. -/// +/// // Implementation: // static void segment_allocate_add(mempool p, uint64 count); static SPIN_LOCK l_mempoolListLock; -static mempool l_mempoolList = NULL; +static mempool l_mempoolList = NULL; static rAthread l_async_thread = NULL; -static ramutex l_async_lock = NULL; -static racond l_async_cond = NULL; +static ramutex l_async_lock = NULL; +static racond l_async_cond = NULL; static volatile int32 l_async_terminate = 0; -static void *mempool_async_allocator(void *x){ - mempool p; - - - while(1){ - if(l_async_terminate > 0) - break; - - EnterSpinLock(&l_mempoolListLock); - - for(p = l_mempoolList; p != NULL; p = p->next){ - - if(p->num_nodes_free < p->elem_realloc_thresh){ - // add new segment. - segment_allocate_add(p, p->elem_realloc_step); - // increase stats counter - InterlockedIncrement64(&p->num_realloc_events); - } - - } - - LeaveSpinLock(&l_mempoolListLock); - - ramutex_lock( l_async_lock ); - racond_wait( l_async_cond, l_async_lock, -1 ); - ramutex_unlock( l_async_lock ); - } - - - return NULL; +static void *mempool_async_allocator(void *x) +{ + mempool p; + + + while (1) { + if (l_async_terminate > 0) + break; + + EnterSpinLock(&l_mempoolListLock); + + for (p = l_mempoolList; p != NULL; p = p->next) { + + if (p->num_nodes_free < p->elem_realloc_thresh) { + // add new segment. + segment_allocate_add(p, p->elem_realloc_step); + // increase stats counter + InterlockedIncrement64(&p->num_realloc_events); + } + + } + + LeaveSpinLock(&l_mempoolListLock); + + ramutex_lock(l_async_lock); + racond_wait(l_async_cond, l_async_lock, -1); + ramutex_unlock(l_async_lock); + } + + + return NULL; }//end: mempool_async_allocator() -void mempool_init(){ - - if(sizeof(struct node)%16 != 0 ){ - ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); - exit(EXIT_FAILURE); - } - - // Global List start - InitializeSpinLock(&l_mempoolListLock); - l_mempoolList = NULL; - - // Initialize mutex + stuff needed for async allocator worker. - l_async_terminate = 0; - l_async_lock = ramutex_create(); - l_async_cond = racond_create(); - - l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); - if(l_async_thread == NULL){ - ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); - exit(EXIT_FAILURE); - } +void mempool_init() +{ + + if (sizeof(struct node)%16 != 0) { + ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); + exit(EXIT_FAILURE); + } + + // Global List start + InitializeSpinLock(&l_mempoolListLock); + l_mempoolList = NULL; + + // Initialize mutex + stuff needed for async allocator worker. + l_async_terminate = 0; + l_async_lock = ramutex_create(); + l_async_cond = racond_create(); + + l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); + if (l_async_thread == NULL) { + ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); + exit(EXIT_FAILURE); + } }//end: mempool_init() -void mempool_final(){ - mempool p, pn; - - ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); - - // Terminate worker / wait until its terminated. - InterlockedIncrement(&l_async_terminate); - racond_signal(l_async_cond); - rathread_wait(l_async_thread, NULL); - - // Destroy cond var and mutex. - racond_destroy( l_async_cond ); - ramutex_destroy( l_async_lock ); - - // Free remaining mempools - // ((bugged code! this should halppen, every mempool should - // be freed by the subsystem that has allocated it.) - // - EnterSpinLock(&l_mempoolListLock); - p = l_mempoolList; - while(1){ - if(p == NULL) - break; - - pn = p->next; - - ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); - mempool_destroy(p); - - p = pn; - } - LeaveSpinLock(&l_mempoolListLock); - +void mempool_final() +{ + mempool p, pn; + + ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); + + // Terminate worker / wait until its terminated. + InterlockedIncrement(&l_async_terminate); + racond_signal(l_async_cond); + rathread_wait(l_async_thread, NULL); + + // Destroy cond var and mutex. + racond_destroy(l_async_cond); + ramutex_destroy(l_async_lock); + + // Free remaining mempools + // ((bugged code! this should halppen, every mempool should + // be freed by the subsystem that has allocated it.) + // + EnterSpinLock(&l_mempoolListLock); + p = l_mempoolList; + while (1) { + if (p == NULL) + break; + + pn = p->next; + + ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); + mempool_destroy(p); + + p = pn; + } + LeaveSpinLock(&l_mempoolListLock); + }//end: mempool_final() -static void segment_allocate_add(mempool p, uint64 count){ - - // Required Memory: - // sz( segment ) - // count * sz( real_node_size ) - // - // where real node size is: - // ALIGN_TO_16( sz( node ) ) + p->elem_size - // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) - // - size_t total_sz; - struct pool_segment *seg = NULL; - struct node *nodeList = NULL; - struct node *node = NULL; - char *ptr = NULL; - uint64 i; - - total_sz = ALIGN_TO_16( sizeof(struct pool_segment) ) - + ( (size_t)count * (sizeof(struct node) + (size_t)p->elem_size) ) ; +static void segment_allocate_add(mempool p, uint64 count) +{ + + // Required Memory: + // sz( segment ) + // count * sz( real_node_size ) + // + // where real node size is: + // ALIGN_TO_16( sz( node ) ) + p->elem_size + // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) + // + size_t total_sz; + struct pool_segment *seg = NULL; + struct node *nodeList = NULL; + struct node *node = NULL; + char *ptr = NULL; + uint64 i; + + total_sz = ALIGN_TO_16(sizeof(struct pool_segment)) + + ((size_t)count * (sizeof(struct node) + (size_t)p->elem_size)) ; #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); + ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); #endif - // allocate! (spin forever until weve got the memory.) - i=0; - while(1){ - ptr = (char*)aMalloc(total_sz); - if(ptr != NULL) break; - - i++; // increase failcount. - if(!(i & 7)){ - ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); + // allocate! (spin forever until weve got the memory.) + i=0; + while (1) { + ptr = (char *)aMalloc(total_sz); + if (ptr != NULL) break; + + i++; // increase failcount. + if (!(i & 7)) { + ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); #ifdef WIN32 - Sleep(1000); + Sleep(1000); #else - sleep(1); + sleep(1); #endif - }else{ - rathread_yield(); /// allow/force vuln. ctxswitch - } - }//endwhile: allocation spinloop. - - // Clear Memory. - memset(ptr, 0x00, total_sz); - - // Initialize segment struct. - seg = (struct pool_segment*)ptr; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - - seg->pool = p; - seg->num_nodes_total = count; - seg->num_bytes = total_sz; - - - // Initialze nodes! - nodeList = NULL; - for(i = 0; i < count; i++){ - node = (struct node*)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; - - node->segment = seg; + } else { + rathread_yield(); /// allow/force vuln. ctxswitch + } + }//endwhile: allocation spinloop. + + // Clear Memory. + memset(ptr, 0x00, total_sz); + + // Initialize segment struct. + seg = (struct pool_segment *)ptr; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + + seg->pool = p; + seg->num_nodes_total = count; + seg->num_bytes = total_sz; + + + // Initialze nodes! + nodeList = NULL; + for (i = 0; i < count; i++) { + node = (struct node *)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; + + node->segment = seg; #ifdef MEMPOOLASSERT - node->used = false; - node->magic = NODE_MAGIC; + node->used = false; + node->magic = NODE_MAGIC; #endif - if(p->onalloc != NULL) p->onalloc( NODE_TO_DATA(node) ); - - node->next = nodeList; - nodeList = node; - } - - - - // Link in Segment. - EnterSpinLock(&p->segmentLock); - seg->next = p->segments; - p->segments = seg; - LeaveSpinLock(&p->segmentLock); - - // Link in Nodes - EnterSpinLock(&p->nodeLock); - nodeList->next = p->free_list; - p->free_list = nodeList; - LeaveSpinLock(&p->nodeLock); - - - // Increase Stats: - InterlockedExchangeAdd64(&p->num_nodes_total, count); - InterlockedExchangeAdd64(&p->num_nodes_free, count); - InterlockedIncrement64(&p->num_segments); - InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); - + if (p->onalloc != NULL) p->onalloc(NODE_TO_DATA(node)); + + node->next = nodeList; + nodeList = node; + } + + + + // Link in Segment. + EnterSpinLock(&p->segmentLock); + seg->next = p->segments; + p->segments = seg; + LeaveSpinLock(&p->segmentLock); + + // Link in Nodes + EnterSpinLock(&p->nodeLock); + nodeList->next = p->free_list; + p->free_list = nodeList; + LeaveSpinLock(&p->nodeLock); + + + // Increase Stats: + InterlockedExchangeAdd64(&p->num_nodes_total, count); + InterlockedExchangeAdd64(&p->num_nodes_free, count); + InterlockedIncrement64(&p->num_segments); + InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); + }//end: segment_allocate_add() mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc){ - //.. - uint64 realloc_thresh; - mempool pool; - pool = (mempool)aCalloc( 1, sizeof(struct mempool) ); - - if(pool == NULL){ - ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool) ); - exit(EXIT_FAILURE); - } - - // Check minimum initial count / realloc count requirements. - if(initial_count < 50) - initial_count = 50; - if(realloc_count < 50) - realloc_count = 50; - - // Set Reallocation threshold to 5% of realloc_count, at least 10. - realloc_thresh = (realloc_count/100)*5; // - if(realloc_thresh < 10) - realloc_thresh = 10; - - // Initialize members.. - pool->name = aStrdup(name); - pool->elem_size = ALIGN_TO_16(elem_size); - pool->elem_realloc_step = realloc_count; - pool->elem_realloc_thresh = realloc_thresh; - pool->onalloc = onNodeAlloc; - pool->ondealloc = onNodeDealloc; - - InitializeSpinLock(&pool->segmentLock); - InitializeSpinLock(&pool->nodeLock); - - // Initial Statistic values: - pool->num_nodes_total = 0; - pool->num_nodes_free = 0; - pool->num_segments = 0; - pool->num_bytes_total = 0; - pool->peak_nodes_used = 0; - pool->num_realloc_events = 0; - - // + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc) +{ + //.. + uint64 realloc_thresh; + mempool pool; + pool = (mempool)aCalloc(1, sizeof(struct mempool)); + + if (pool == NULL) { + ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool)); + exit(EXIT_FAILURE); + } + + // Check minimum initial count / realloc count requirements. + if (initial_count < 50) + initial_count = 50; + if (realloc_count < 50) + realloc_count = 50; + + // Set Reallocation threshold to 5% of realloc_count, at least 10. + realloc_thresh = (realloc_count/100)*5; // + if (realloc_thresh < 10) + realloc_thresh = 10; + + // Initialize members.. + pool->name = aStrdup(name); + pool->elem_size = ALIGN_TO_16(elem_size); + pool->elem_realloc_step = realloc_count; + pool->elem_realloc_thresh = realloc_thresh; + pool->onalloc = onNodeAlloc; + pool->ondealloc = onNodeDealloc; + + InitializeSpinLock(&pool->segmentLock); + InitializeSpinLock(&pool->nodeLock); + + // Initial Statistic values: + pool->num_nodes_total = 0; + pool->num_nodes_free = 0; + pool->num_segments = 0; + pool->num_bytes_total = 0; + pool->peak_nodes_used = 0; + pool->num_realloc_events = 0; + + // #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); + ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); #endif - // Allocate first segment directly :) - segment_allocate_add(pool, initial_count); - + // Allocate first segment directly :) + segment_allocate_add(pool, initial_count); + + + // Add Pool to the global pool list + EnterSpinLock(&l_mempoolListLock); + pool->next = l_mempoolList; + l_mempoolList = pool; + LeaveSpinLock(&l_mempoolListLock); - // Add Pool to the global pool list - EnterSpinLock(&l_mempoolListLock); - pool->next = l_mempoolList; - l_mempoolList = pool; - LeaveSpinLock(&l_mempoolListLock); - - return pool; + return pool; }//end: mempool_create() -void mempool_destroy(mempool p){ - struct pool_segment *seg, *segnext; - struct node *niter; - mempool piter, pprev; - char *ptr; - int64 i; +void mempool_destroy(mempool p) +{ + struct pool_segment *seg, *segnext; + struct node *niter; + mempool piter, pprev; + char *ptr; + int64 i; #ifdef MEMPOOL_DEBUG ShowDebug("Mempool [%s] Destroy\n", p->name); #endif - - // Unlink from global list. - EnterSpinLock(&l_mempoolListLock); - piter = l_mempoolList; - pprev = l_mempoolList; - while(1){ - if(piter == NULL) - break; - - - if(piter == p){ - // unlink from list, - // - if(pprev == l_mempoolList){ - // this (p) is list begin. so set next as head. - l_mempoolList = p->next; - }else{ - // replace prevs next wuth our next. - pprev->next = p->next; - } - break; - } - - pprev = piter; - piter = piter->next; - } - - p->next = NULL; - LeaveSpinLock(&l_mempoolListLock); - - - // Get both locks. - EnterSpinLock(&p->segmentLock); - EnterSpinLock(&p->nodeLock); - - - if(p->num_nodes_free != p->num_nodes_total) - ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free) ); - - // Free All Segments (this will also free all nodes) - // The segment pointer is the base pointer to the whole segment. - seg = p->segments; - while(1){ - if(seg == NULL) - break; - - segnext = seg->next; - - // .. - if(p->ondealloc != NULL){ - // walk over the segment, and call dealloc callback! - ptr = (char*)seg; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - for(i = 0; i < seg->num_nodes_total; i++){ - niter = (struct node*)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; + + // Unlink from global list. + EnterSpinLock(&l_mempoolListLock); + piter = l_mempoolList; + pprev = l_mempoolList; + while (1) { + if (piter == NULL) + break; + + + if (piter == p) { + // unlink from list, + // + if (pprev == l_mempoolList) { + // this (p) is list begin. so set next as head. + l_mempoolList = p->next; + } else { + // replace prevs next wuth our next. + pprev->next = p->next; + } + break; + } + + pprev = piter; + piter = piter->next; + } + + p->next = NULL; + LeaveSpinLock(&l_mempoolListLock); + + + // Get both locks. + EnterSpinLock(&p->segmentLock); + EnterSpinLock(&p->nodeLock); + + + if (p->num_nodes_free != p->num_nodes_total) + ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free)); + + // Free All Segments (this will also free all nodes) + // The segment pointer is the base pointer to the whole segment. + seg = p->segments; + while (1) { + if (seg == NULL) + break; + + segnext = seg->next; + + // .. + if (p->ondealloc != NULL) { + // walk over the segment, and call dealloc callback! + ptr = (char *)seg; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + for (i = 0; i < seg->num_nodes_total; i++) { + niter = (struct node *)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; #ifdef MEMPOOLASSERT - if(niter->magic != NODE_MAGIC){ - ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); - continue; - } + if (niter->magic != NODE_MAGIC) { + ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); + continue; + } #endif - - p->ondealloc( NODE_TO_DATA(niter) ); - - - } - }//endif: ondealloc callback? - - // simple .. - aFree(seg); - - seg = segnext; - } - - // Clear node ptr - p->free_list = NULL; - InterlockedExchange64(&p->num_nodes_free, 0); - InterlockedExchange64(&p->num_nodes_total, 0); - InterlockedExchange64(&p->num_segments, 0); - InterlockedExchange64(&p->num_bytes_total, 0); - - LeaveSpinLock(&p->nodeLock); - LeaveSpinLock(&p->segmentLock); - - // Free pool itself :D - aFree(p->name); - aFree(p); + + p->ondealloc(NODE_TO_DATA(niter)); + + + } + }//endif: ondealloc callback? + + // simple .. + aFree(seg); + + seg = segnext; + } + + // Clear node ptr + p->free_list = NULL; + InterlockedExchange64(&p->num_nodes_free, 0); + InterlockedExchange64(&p->num_nodes_total, 0); + InterlockedExchange64(&p->num_segments, 0); + InterlockedExchange64(&p->num_bytes_total, 0); + + LeaveSpinLock(&p->nodeLock); + LeaveSpinLock(&p->segmentLock); + + // Free pool itself :D + aFree(p->name); + aFree(p); }//end: mempool_destroy() -void *mempool_node_get(mempool p){ - struct node *node; - int64 num_used; - - if(p->num_nodes_free < p->elem_realloc_thresh) - racond_signal(l_async_cond); - - while(1){ - - EnterSpinLock(&p->nodeLock); - - node = p->free_list; - if(node != NULL) - p->free_list = node->next; - - LeaveSpinLock(&p->nodeLock); - - if(node != NULL) - break; - - rathread_yield(); - } - - InterlockedDecrement64(&p->num_nodes_free); - - // Update peak value - num_used = (p->num_nodes_total - p->num_nodes_free); - if(num_used > p->peak_nodes_used){ - InterlockedExchange64(&p->peak_nodes_used, num_used); - } - +void *mempool_node_get(mempool p) +{ + struct node *node; + int64 num_used; + + if (p->num_nodes_free < p->elem_realloc_thresh) + racond_signal(l_async_cond); + + while (1) { + + EnterSpinLock(&p->nodeLock); + + node = p->free_list; + if (node != NULL) + p->free_list = node->next; + + LeaveSpinLock(&p->nodeLock); + + if (node != NULL) + break; + + rathread_yield(); + } + + InterlockedDecrement64(&p->num_nodes_free); + + // Update peak value + num_used = (p->num_nodes_total - p->num_nodes_free); + if (num_used > p->peak_nodes_used) { + InterlockedExchange64(&p->peak_nodes_used, num_used); + } + #ifdef MEMPOOLASSERT - node->used = true; + node->used = true; #endif - return NODE_TO_DATA(node); + return NODE_TO_DATA(node); }//end: mempool_node_get() -void mempool_node_put(mempool p, void *data){ - struct node *node; - - node = DATA_TO_NODE(data); +void mempool_node_put(mempool p, void *data) +{ + struct node *node; + + node = DATA_TO_NODE(data); #ifdef MEMPOOLASSERT - if(node->magic != NODE_MAGIC){ - ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); - return; // lost, - } - - { - struct pool_segment *node_seg = node->segment; - if(node_seg->pool != p){ - ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); - return; - } - } - - // reset used flag. - node->used = false; + if (node->magic != NODE_MAGIC) { + ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); + return; // lost, + } + + { + struct pool_segment *node_seg = node->segment; + if (node_seg->pool != p) { + ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); + return; + } + } + + // reset used flag. + node->used = false; #endif - // - EnterSpinLock(&p->nodeLock); - node->next = p->free_list; - p->free_list = node; - LeaveSpinLock(&p->nodeLock); - - InterlockedIncrement64(&p->num_nodes_free); + // + EnterSpinLock(&p->nodeLock); + node->next = p->free_list; + p->free_list = node; + LeaveSpinLock(&p->nodeLock); + + InterlockedIncrement64(&p->num_nodes_free); }//end: mempool_node_put() -mempool_stats mempool_get_stats(mempool pool){ - mempool_stats stats; - - // initialize all with zeros - memset(&stats, 0x00, sizeof(mempool_stats)); - - stats.num_nodes_total = pool->num_nodes_total; - stats.num_nodes_free = pool->num_nodes_free; - stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); - stats.num_segments = pool->num_segments; - stats.num_realloc_events= pool->num_realloc_events; - stats.peak_nodes_used = pool->peak_nodes_used; - stats.num_bytes_total = pool->num_bytes_total; - - // Pushing such a large block over the stack as return value isnt nice - // but lazy :) and should be okay in this case (Stats / Debug..) - // if you dont like it - feel free and refactor it. - return stats; +mempool_stats mempool_get_stats(mempool pool) +{ + mempool_stats stats; + + // initialize all with zeros + memset(&stats, 0x00, sizeof(mempool_stats)); + + stats.num_nodes_total = pool->num_nodes_total; + stats.num_nodes_free = pool->num_nodes_free; + stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); + stats.num_segments = pool->num_segments; + stats.num_realloc_events= pool->num_realloc_events; + stats.peak_nodes_used = pool->peak_nodes_used; + stats.num_bytes_total = pool->num_bytes_total; + + // Pushing such a large block over the stack as return value isnt nice + // but lazy :) and should be okay in this case (Stats / Debug..) + // if you dont like it - feel free and refactor it. + return stats; }//end: mempool_get_stats() diff --git a/src/common/mempool.h b/src/common/mempool.h index aeaebe7fe..9c4f1563e 100644 --- a/src/common/mempool.h +++ b/src/common/mempool.h @@ -8,67 +8,67 @@ typedef struct mempool *mempool; typedef void (*memPoolOnNodeAllocationProc)(void *ptr); typedef void (*memPoolOnNodeDeallocationProc)(void *ptr); -typedef struct mempool_stats{ - int64 num_nodes_total; - int64 num_nodes_free; - int64 num_nodes_used; - - int64 num_segments; - int64 num_realloc_events; - - int64 peak_nodes_used; - - int64 num_bytes_total; +typedef struct mempool_stats { + int64 num_nodes_total; + int64 num_nodes_free; + int64 num_nodes_used; + + int64 num_segments; + int64 num_realloc_events; + + int64 peak_nodes_used; + + int64 num_bytes_total; } mempool_stats; -// +// void mempool_init(); void mempool_final(); -/** +/** * Creates a new Mempool * * @param name - Name of the pool (used for debug / error messages) * @param elem_size - size of each element - * @param initial_count - preallocation count + * @param initial_count - preallocation count * @param realloc_count - #no of nodes being allocated when pool is running empty. * @param onNodeAlloc - Node Allocation callback (see @note!) * @param onNodeDealloc - Node Deallocation callback (see @note!) * * @note: - * The onNode(De)alloc callbacks are only called once during segment allocation - * (pool initialization / rallocation ) + * The onNode(De)alloc callbacks are only called once during segment allocation + * (pool initialization / rallocation ) * you can use this callbacks for example to initlaize a mutex or somethingelse - * you definitly need during runtime + * you definitly need during runtime * * @return not NULL */ mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc); - - + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc); + + /** * Destroys a Mempool - * + * * @param pool - the mempool to destroy * * @note: - * Everything gets deallocated, regardless if everything was freed properly! - * So you have to ensure that all references are cleared properly! + * Everything gets deallocated, regardless if everything was freed properly! + * So you have to ensure that all references are cleared properly! */ void mempool_destroy(mempool pool); /** * Gets a new / empty node from the given mempool. - * + * * @param pool - the pool to get an empty node from. * * @return Address of empty Node @@ -80,12 +80,12 @@ void *mempool_node_get(mempool pool); * Returns the given node to the given mempool * * @param pool - the pool to put the node, to - * @param node - the node to return + * @param node - the node to return */ void mempool_node_put(mempool pool, void *node); -/** +/** * Returns Statistics for the given mempool * * @param pool - the pool to get thats for diff --git a/src/common/mmo.h b/src/common/mmo.h index 5f6108b33..4236eb4c6 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _MMO_H_ -#define _MMO_H_ +#ifndef _MMO_H_ +#define _MMO_H_ #include "cbasetypes.h" #include @@ -46,25 +46,25 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120410 - //#define PACKETVER 20111116 +#define PACKETVER 20120410 +//#define PACKETVER 20111116 #endif //Remove/Comment this line to disable sc_data saving. [Skotlex] -#define ENABLE_SC_SAVING +#define ENABLE_SC_SAVING //Remove/Comment this line to disable server-side hot-key saving support [Skotlex] //Note that newer clients no longer save hotkeys in the registry! #define HOTKEY_SAVING #if PACKETVER < 20090603 - // (27 = 9 skills x 3 bars) (0x02b9,191) - #define MAX_HOTKEYS 27 +// (27 = 9 skills x 3 bars) (0x02b9,191) +#define MAX_HOTKEYS 27 #elif PACKETVER < 20090617 - // (36 = 9 skills x 4 bars) (0x07d9,254) - #define MAX_HOTKEYS 36 +// (36 = 9 skills x 4 bars) (0x07d9,254) +#define MAX_HOTKEYS 36 #else - // (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) - #define MAX_HOTKEYS 38 +// (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) +#define MAX_HOTKEYS 38 #endif #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps @@ -91,13 +91,13 @@ #define MAX_STORAGE 600 #define MAX_GUILD_STORAGE 600 #define MAX_PARTY 12 -#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] -#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] +#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] #define MAX_GUILDEXPULSION 32 #define MAX_GUILDALLIANCE 16 -#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] +#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 -#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] +#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] #define MAX_QUEST_DB 2000 //Max quests that the server will load #define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest @@ -140,7 +140,7 @@ //Base Homun skill. #define HM_SKILLBASE 8001 #define MAX_HOMUNSKILL 43 -#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. +#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. #define HM_CLASS_BASE 6001 #define HM_CLASS_MAX (HM_CLASS_BASE+MAX_HOMUNCULUS_CLASS-1) @@ -163,20 +163,20 @@ #define EL_CLASS_MAX (EL_CLASS_BASE+MAX_ELEMENTAL_CLASS-1) enum item_types { - IT_HEALING = 0, - IT_UNKNOWN, //1 - IT_USABLE, //2 - IT_ETC, //3 - IT_WEAPON, //4 - IT_ARMOR, //5 - IT_CARD, //6 - IT_PETEGG, //7 - IT_PETARMOR,//8 - IT_UNKNOWN2,//9 - IT_AMMO, //10 - IT_DELAYCONSUME,//11 - IT_CASH = 18, - IT_MAX + IT_HEALING = 0, + IT_UNKNOWN, //1 + IT_USABLE, //2 + IT_ETC, //3 + IT_WEAPON, //4 + IT_ARMOR, //5 + IT_CARD, //6 + IT_PETEGG, //7 + IT_PETARMOR,//8 + IT_UNKNOWN2,//9 + IT_AMMO, //10 + IT_DELAYCONSUME,//11 + IT_CASH = 18, + IT_MAX }; @@ -184,556 +184,555 @@ enum item_types { typedef enum quest_state { Q_INACTIVE, Q_ACTIVE, Q_COMPLETE } quest_state; struct quest { - int quest_id; - unsigned int time; - int count[MAX_QUEST_OBJECTIVES]; - quest_state state; + int quest_id; + unsigned int time; + int count[MAX_QUEST_OBJECTIVES]; + quest_state state; }; struct item { - int id; - short nameid; - short amount; - unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) - char identify; - char refine; - char attribute; - short card[MAX_SLOTS]; - unsigned int expire_time; - char favorite; + int id; + short nameid; + short amount; + unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) + char identify; + char refine; + char attribute; + short card[MAX_SLOTS]; + unsigned int expire_time; + char favorite; }; struct point { - unsigned short map; - short x,y; + unsigned short map; + short x,y; }; -enum e_skill_flag -{ - SKILL_FLAG_PERMANENT, - SKILL_FLAG_TEMPORARY, - SKILL_FLAG_PLAGIARIZED, - SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' - //... +enum e_skill_flag { + SKILL_FLAG_PERMANENT, + SKILL_FLAG_TEMPORARY, + SKILL_FLAG_PLAGIARIZED, + SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' + //... }; struct s_skill { - unsigned short id; - unsigned char lv; - unsigned char flag; // see enum e_skill_flag + unsigned short id; + unsigned char lv; + unsigned char flag; // see enum e_skill_flag }; struct global_reg { - char str[32]; - char value[256]; + char str[32]; + char value[256]; }; //Holds array of global registries, used by the char server and converter. struct accreg { - int account_id, char_id; - int reg_num; - struct global_reg reg[MAX_REG_NUM]; + int account_id, char_id; + int reg_num; + struct global_reg reg[MAX_REG_NUM]; }; //For saving status changes across sessions. [Skotlex] struct status_change_data { - unsigned short type; //SC_type - long val1, val2, val3, val4, tick; //Remaining duration. + unsigned short type; //SC_type + long val1, val2, val3, val4, tick; //Remaining duration. }; struct storage_data { - int storage_amount; - struct item items[MAX_STORAGE]; + int storage_amount; + struct item items[MAX_STORAGE]; }; struct guild_storage { - int dirty; - int guild_id; - short storage_status; - short storage_amount; - struct item items[MAX_GUILD_STORAGE]; + int dirty; + int guild_id; + short storage_status; + short storage_amount; + struct item items[MAX_GUILD_STORAGE]; }; struct s_pet { - int account_id; - int char_id; - int pet_id; - short class_; - short level; - short egg_id;//pet egg id - short equip;//pet equip name_id - short intimate;//pet friendly - short hungry;//pet hungry - char name[NAME_LENGTH]; - char rename_flag; - char incuvate; -}; - -struct s_homunculus { //[orn] - char name[NAME_LENGTH]; - int hom_id; - int char_id; - short class_; - short prev_class; - int hp,max_hp,sp,max_sp; - unsigned int intimacy; //[orn] - short hunger; - struct s_skill hskill[MAX_HOMUNSKILL]; //albator - short skillpts; - short level; - unsigned int exp; - short rename_flag; - short vaporize; //albator - int str ; - int agi ; - int vit ; - int int_ ; - int dex ; - int luk ; + int account_id; + int char_id; + int pet_id; + short class_; + short level; + short egg_id;//pet egg id + short equip;//pet equip name_id + short intimate;//pet friendly + short hungry;//pet hungry + char name[NAME_LENGTH]; + char rename_flag; + char incuvate; +}; + +struct s_homunculus { //[orn] + char name[NAME_LENGTH]; + int hom_id; + int char_id; + short class_; + short prev_class; + int hp,max_hp,sp,max_sp; + unsigned int intimacy; //[orn] + short hunger; + struct s_skill hskill[MAX_HOMUNSKILL]; //albator + short skillpts; + short level; + unsigned int exp; + short rename_flag; + short vaporize; //albator + int str ; + int agi ; + int vit ; + int int_ ; + int dex ; + int luk ; }; struct s_mercenary { - int mercenary_id; - int char_id; - short class_; - int hp, sp; - unsigned int kill_count; - unsigned int life_time; + int mercenary_id; + int char_id; + short class_; + int hp, sp; + unsigned int kill_count; + unsigned int life_time; }; struct s_elemental { - int elemental_id; - int char_id; - short class_; - int mode; - int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; - int life_time; + int elemental_id; + int char_id; + short class_; + int mode; + int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; + int life_time; }; struct s_friend { - int account_id; - int char_id; - char name[NAME_LENGTH]; + int account_id; + int char_id; + char name[NAME_LENGTH]; }; #ifdef HOTKEY_SAVING struct hotkey { - unsigned int id; - unsigned short lv; - unsigned char type; // 0: item, 1: skill + unsigned int id; + unsigned short lv; + unsigned char type; // 0: item, 1: skill }; #endif struct mmo_charstatus { - int char_id; - int account_id; - int partner_id; - int father; - int mother; - int child; - - unsigned int base_exp,job_exp; - int zeny; - - short class_; - unsigned int status_point,skill_point; - int hp,max_hp,sp,max_sp; - unsigned int option; - short manner; - unsigned char karma; - short hair,hair_color,clothes_color; - int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; - int fame; - - // Mercenary Guilds Rank - int arch_faith, arch_calls; - int spear_faith, spear_calls; - int sword_faith, sword_calls; - - short weapon; // enum weapon_type - short shield; // view-id - short head_top,head_mid,head_bottom; - short robe; - - char name[NAME_LENGTH]; - unsigned int base_level,job_level; - short str,agi,vit,int_,dex,luk; - unsigned char slot,sex; - - uint32 mapip; - uint16 mapport; - - struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; - struct item inventory[MAX_INVENTORY],cart[MAX_CART]; - struct storage_data storage; - struct s_skill skill[MAX_SKILL]; - - struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] + int char_id; + int account_id; + int partner_id; + int father; + int mother; + int child; + + unsigned int base_exp,job_exp; + int zeny; + + short class_; + unsigned int status_point,skill_point; + int hp,max_hp,sp,max_sp; + unsigned int option; + short manner; + unsigned char karma; + short hair,hair_color,clothes_color; + int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; + int fame; + + // Mercenary Guilds Rank + int arch_faith, arch_calls; + int spear_faith, spear_calls; + int sword_faith, sword_calls; + + short weapon; // enum weapon_type + short shield; // view-id + short head_top,head_mid,head_bottom; + short robe; + + char name[NAME_LENGTH]; + unsigned int base_level,job_level; + short str,agi,vit,int_,dex,luk; + unsigned char slot,sex; + + uint32 mapip; + uint16 mapport; + + struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; + struct item inventory[MAX_INVENTORY],cart[MAX_CART]; + struct storage_data storage; + struct s_skill skill[MAX_SKILL]; + + struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] #ifdef HOTKEY_SAVING - struct hotkey hotkeys[MAX_HOTKEYS]; + struct hotkey hotkeys[MAX_HOTKEYS]; #endif - bool show_equip; - short rename; + bool show_equip; + short rename; - time_t delete_date; + time_t delete_date; }; typedef enum mail_status { - MAIL_NEW, - MAIL_UNREAD, - MAIL_READ, + MAIL_NEW, + MAIL_UNREAD, + MAIL_READ, } mail_status; struct mail_message { - int id; - int send_id; - char send_name[NAME_LENGTH]; - int dest_id; - char dest_name[NAME_LENGTH]; - char title[MAIL_TITLE_LENGTH]; - char body[MAIL_BODY_LENGTH]; + int id; + int send_id; + char send_name[NAME_LENGTH]; + int dest_id; + char dest_name[NAME_LENGTH]; + char title[MAIL_TITLE_LENGTH]; + char body[MAIL_BODY_LENGTH]; - mail_status status; - time_t timestamp; // marks when the message was sent + mail_status status; + time_t timestamp; // marks when the message was sent - int zeny; - struct item item; + int zeny; + struct item item; }; struct mail_data { - short amount; - bool full; - short unchecked, unread; - struct mail_message msg[MAIL_MAX_INBOX]; + short amount; + bool full; + short unchecked, unread; + struct mail_message msg[MAIL_MAX_INBOX]; }; struct auction_data { - unsigned int auction_id; - int seller_id; - char seller_name[NAME_LENGTH]; - int buyer_id; - char buyer_name[NAME_LENGTH]; - - struct item item; - // This data is required for searching, as itemdb is not read by char server - char item_name[ITEM_NAME_LENGTH]; - short type; - - unsigned short hours; - int price, buynow; - time_t timestamp; // auction's end time - int auction_end_timer; + unsigned int auction_id; + int seller_id; + char seller_name[NAME_LENGTH]; + int buyer_id; + char buyer_name[NAME_LENGTH]; + + struct item item; + // This data is required for searching, as itemdb is not read by char server + char item_name[ITEM_NAME_LENGTH]; + short type; + + unsigned short hours; + int price, buynow; + time_t timestamp; // auction's end time + int auction_end_timer; }; struct registry { - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; - int account_num; - struct global_reg account[ACCOUNT_REG_NUM]; - int account2_num; - struct global_reg account2[ACCOUNT_REG2_NUM]; + int global_num; + struct global_reg global[GLOBAL_REG_NUM]; + int account_num; + struct global_reg account[ACCOUNT_REG_NUM]; + int account2_num; + struct global_reg account2[ACCOUNT_REG2_NUM]; }; struct party_member { - int account_id; - int char_id; - char name[NAME_LENGTH]; - unsigned short class_; - unsigned short map; - unsigned short lv; - unsigned leader : 1, - online : 1; + int account_id; + int char_id; + char name[NAME_LENGTH]; + unsigned short class_; + unsigned short map; + unsigned short lv; + unsigned leader : 1, + online : 1; }; struct party { - int party_id; - char name[NAME_LENGTH]; - unsigned char count; //Count of online characters. - unsigned exp : 1, - item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. - struct party_member member[MAX_PARTY]; + int party_id; + char name[NAME_LENGTH]; + unsigned char count; //Count of online characters. + unsigned exp : 1, + item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. + struct party_member member[MAX_PARTY]; }; struct map_session_data; struct guild_member { - int account_id, char_id; - short hair,hair_color,gender,class_,lv; - uint64 exp; - int exp_payper; - short online,position; - char name[NAME_LENGTH]; - struct map_session_data *sd; - unsigned char modified; + int account_id, char_id; + short hair,hair_color,gender,class_,lv; + uint64 exp; + int exp_payper; + short online,position; + char name[NAME_LENGTH]; + struct map_session_data *sd; + unsigned char modified; }; struct guild_position { - char name[NAME_LENGTH]; - int mode; - int exp_mode; - unsigned char modified; + char name[NAME_LENGTH]; + int mode; + int exp_mode; + unsigned char modified; }; struct guild_alliance { - int opposition; - int guild_id; - char name[NAME_LENGTH]; + int opposition; + int guild_id; + char name[NAME_LENGTH]; }; struct guild_expulsion { - char name[NAME_LENGTH]; - char mes[40]; - int account_id; + char name[NAME_LENGTH]; + char mes[40]; + int account_id; }; struct guild_skill { - int id,lv; + int id,lv; }; struct guild { - int guild_id; - short guild_lv, connect_member, max_member, average_lv; - uint64 exp; - unsigned int next_exp; - int skill_point; - char name[NAME_LENGTH],master[NAME_LENGTH]; - struct guild_member member[MAX_GUILD]; - struct guild_position position[MAX_GUILDPOSITION]; - char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; - int emblem_len,emblem_id; - char emblem_data[2048]; - struct guild_alliance alliance[MAX_GUILDALLIANCE]; - struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; - struct guild_skill skill[MAX_GUILDSKILL]; - - unsigned short save_flag; // for TXT saving + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + uint64 exp; + unsigned int next_exp; + int skill_point; + char name[NAME_LENGTH],master[NAME_LENGTH]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; + int emblem_len,emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; + struct guild_skill skill[MAX_GUILDSKILL]; + + unsigned short save_flag; // for TXT saving }; struct guild_castle { - int castle_id; - int mapindex; - char castle_name[NAME_LENGTH]; - char castle_event[NAME_LENGTH]; - int guild_id; - int economy; - int defense; - int triggerE; - int triggerD; - int nextTime; - int payTime; - int createTime; - int visibleC; - struct { - unsigned visible : 1; - int id; // object id - } guardian[MAX_GUARDIANS]; - int* temp_guardians; // ids of temporary guardians (mobs) - int temp_guardians_max; + int castle_id; + int mapindex; + char castle_name[NAME_LENGTH]; + char castle_event[NAME_LENGTH]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + struct { + unsigned visible : 1; + int id; // object id + } guardian[MAX_GUARDIANS]; + int *temp_guardians; // ids of temporary guardians (mobs) + int temp_guardians_max; }; struct fame_list { - int id; - int fame; - char name[NAME_LENGTH]; + int id; + int fame; + char name[NAME_LENGTH]; }; -enum { //Change Guild Infos - GBI_EXP =1, // Guild Experience (EXP) - GBI_GUILDLV, // Guild level - GBI_SKILLPOINT, // Guild skillpoints - GBI_SKILLLV, // Guild skilllv ?? seem unused +enum { //Change Guild Infos + GBI_EXP =1, // Guild Experience (EXP) + GBI_GUILDLV, // Guild level + GBI_SKILLPOINT, // Guild skillpoints + GBI_SKILLLV, // Guild skilllv ?? seem unused }; enum { //Change Member Infos - GMI_POSITION =0, - GMI_EXP, - GMI_HAIR, - GMI_HAIR_COLOR, - GMI_GENDER, - GMI_CLASS, - GMI_LEVEL, + GMI_POSITION =0, + GMI_EXP, + GMI_HAIR, + GMI_HAIR_COLOR, + GMI_GENDER, + GMI_CLASS, + GMI_LEVEL, }; enum { - GD_SKILLBASE=10000, - GD_APPROVAL=10000, - GD_KAFRACONTRACT=10001, - GD_GUARDRESEARCH=10002, - GD_GUARDUP=10003, - GD_EXTENSION=10004, - GD_GLORYGUILD=10005, - GD_LEADERSHIP=10006, - GD_GLORYWOUNDS=10007, - GD_SOULCOLD=10008, - GD_HAWKEYES=10009, - GD_BATTLEORDER=10010, - GD_REGENERATION=10011, - GD_RESTORE=10012, - GD_EMERGENCYCALL=10013, - GD_DEVELOPMENT=10014, - GD_MAX, + GD_SKILLBASE=10000, + GD_APPROVAL=10000, + GD_KAFRACONTRACT=10001, + GD_GUARDRESEARCH=10002, + GD_GUARDUP=10003, + GD_EXTENSION=10004, + GD_GLORYGUILD=10005, + GD_LEADERSHIP=10006, + GD_GLORYWOUNDS=10007, + GD_SOULCOLD=10008, + GD_HAWKEYES=10009, + GD_BATTLEORDER=10010, + GD_REGENERATION=10011, + GD_RESTORE=10012, + GD_EMERGENCYCALL=10013, + GD_DEVELOPMENT=10014, + GD_MAX, }; //These mark the ID of the jobs, as expected by the client. [Skotlex] enum { - JOB_NOVICE, - JOB_SWORDMAN, - JOB_MAGE, - JOB_ARCHER, - JOB_ACOLYTE, - JOB_MERCHANT, - JOB_THIEF, - JOB_KNIGHT, - JOB_PRIEST, - JOB_WIZARD, - JOB_BLACKSMITH, - JOB_HUNTER, - JOB_ASSASSIN, - JOB_KNIGHT2, - JOB_CRUSADER, - JOB_MONK, - JOB_SAGE, - JOB_ROGUE, - JOB_ALCHEMIST, - JOB_BARD, - JOB_DANCER, - JOB_CRUSADER2, - JOB_WEDDING, - JOB_SUPER_NOVICE, - JOB_GUNSLINGER, - JOB_NINJA, - JOB_XMAS, - JOB_SUMMER, - JOB_MAX_BASIC, - - JOB_NOVICE_HIGH = 4001, - JOB_SWORDMAN_HIGH, - JOB_MAGE_HIGH, - JOB_ARCHER_HIGH, - JOB_ACOLYTE_HIGH, - JOB_MERCHANT_HIGH, - JOB_THIEF_HIGH, - JOB_LORD_KNIGHT, - JOB_HIGH_PRIEST, - JOB_HIGH_WIZARD, - JOB_WHITESMITH, - JOB_SNIPER, - JOB_ASSASSIN_CROSS, - JOB_LORD_KNIGHT2, - JOB_PALADIN, - JOB_CHAMPION, - JOB_PROFESSOR, - JOB_STALKER, - JOB_CREATOR, - JOB_CLOWN, - JOB_GYPSY, - JOB_PALADIN2, - - JOB_BABY, - JOB_BABY_SWORDMAN, - JOB_BABY_MAGE, - JOB_BABY_ARCHER, - JOB_BABY_ACOLYTE, - JOB_BABY_MERCHANT, - JOB_BABY_THIEF, - JOB_BABY_KNIGHT, - JOB_BABY_PRIEST, - JOB_BABY_WIZARD, - JOB_BABY_BLACKSMITH, - JOB_BABY_HUNTER, - JOB_BABY_ASSASSIN, - JOB_BABY_KNIGHT2, - JOB_BABY_CRUSADER, - JOB_BABY_MONK, - JOB_BABY_SAGE, - JOB_BABY_ROGUE, - JOB_BABY_ALCHEMIST, - JOB_BABY_BARD, - JOB_BABY_DANCER, - JOB_BABY_CRUSADER2, - JOB_SUPER_BABY, - - JOB_TAEKWON, - JOB_STAR_GLADIATOR, - JOB_STAR_GLADIATOR2, - JOB_SOUL_LINKER, - - JOB_GANGSI, - JOB_DEATH_KNIGHT, - JOB_DARK_COLLECTOR, - - JOB_RUNE_KNIGHT = 4054, - JOB_WARLOCK, - JOB_RANGER, - JOB_ARCH_BISHOP, - JOB_MECHANIC, - JOB_GUILLOTINE_CROSS, - - JOB_RUNE_KNIGHT_T, - JOB_WARLOCK_T, - JOB_RANGER_T, - JOB_ARCH_BISHOP_T, - JOB_MECHANIC_T, - JOB_GUILLOTINE_CROSS_T, - - JOB_ROYAL_GUARD, - JOB_SORCERER, - JOB_MINSTREL, - JOB_WANDERER, - JOB_SURA, - JOB_GENETIC, - JOB_SHADOW_CHASER, - - JOB_ROYAL_GUARD_T, - JOB_SORCERER_T, - JOB_MINSTREL_T, - JOB_WANDERER_T, - JOB_SURA_T, - JOB_GENETIC_T, - JOB_SHADOW_CHASER_T, - - JOB_RUNE_KNIGHT2, - JOB_RUNE_KNIGHT_T2, - JOB_ROYAL_GUARD2, - JOB_ROYAL_GUARD_T2, - JOB_RANGER2, - JOB_RANGER_T2, - JOB_MECHANIC2, - JOB_MECHANIC_T2, - - JOB_BABY_RUNE = 4096, - JOB_BABY_WARLOCK, - JOB_BABY_RANGER, - JOB_BABY_BISHOP, - JOB_BABY_MECHANIC, - JOB_BABY_CROSS, - - JOB_BABY_GUARD, - JOB_BABY_SORCERER, - JOB_BABY_MINSTREL, - JOB_BABY_WANDERER, - JOB_BABY_SURA, - JOB_BABY_GENETIC, - JOB_BABY_CHASER, - - JOB_BABY_RUNE2, - JOB_BABY_GUARD2, - JOB_BABY_RANGER2, - JOB_BABY_MECHANIC2, - - JOB_SUPER_NOVICE_E = 4190, - JOB_SUPER_BABY_E, - - JOB_KAGEROU = 4211, - JOB_OBORO, - - JOB_MAX, + JOB_NOVICE, + JOB_SWORDMAN, + JOB_MAGE, + JOB_ARCHER, + JOB_ACOLYTE, + JOB_MERCHANT, + JOB_THIEF, + JOB_KNIGHT, + JOB_PRIEST, + JOB_WIZARD, + JOB_BLACKSMITH, + JOB_HUNTER, + JOB_ASSASSIN, + JOB_KNIGHT2, + JOB_CRUSADER, + JOB_MONK, + JOB_SAGE, + JOB_ROGUE, + JOB_ALCHEMIST, + JOB_BARD, + JOB_DANCER, + JOB_CRUSADER2, + JOB_WEDDING, + JOB_SUPER_NOVICE, + JOB_GUNSLINGER, + JOB_NINJA, + JOB_XMAS, + JOB_SUMMER, + JOB_MAX_BASIC, + + JOB_NOVICE_HIGH = 4001, + JOB_SWORDMAN_HIGH, + JOB_MAGE_HIGH, + JOB_ARCHER_HIGH, + JOB_ACOLYTE_HIGH, + JOB_MERCHANT_HIGH, + JOB_THIEF_HIGH, + JOB_LORD_KNIGHT, + JOB_HIGH_PRIEST, + JOB_HIGH_WIZARD, + JOB_WHITESMITH, + JOB_SNIPER, + JOB_ASSASSIN_CROSS, + JOB_LORD_KNIGHT2, + JOB_PALADIN, + JOB_CHAMPION, + JOB_PROFESSOR, + JOB_STALKER, + JOB_CREATOR, + JOB_CLOWN, + JOB_GYPSY, + JOB_PALADIN2, + + JOB_BABY, + JOB_BABY_SWORDMAN, + JOB_BABY_MAGE, + JOB_BABY_ARCHER, + JOB_BABY_ACOLYTE, + JOB_BABY_MERCHANT, + JOB_BABY_THIEF, + JOB_BABY_KNIGHT, + JOB_BABY_PRIEST, + JOB_BABY_WIZARD, + JOB_BABY_BLACKSMITH, + JOB_BABY_HUNTER, + JOB_BABY_ASSASSIN, + JOB_BABY_KNIGHT2, + JOB_BABY_CRUSADER, + JOB_BABY_MONK, + JOB_BABY_SAGE, + JOB_BABY_ROGUE, + JOB_BABY_ALCHEMIST, + JOB_BABY_BARD, + JOB_BABY_DANCER, + JOB_BABY_CRUSADER2, + JOB_SUPER_BABY, + + JOB_TAEKWON, + JOB_STAR_GLADIATOR, + JOB_STAR_GLADIATOR2, + JOB_SOUL_LINKER, + + JOB_GANGSI, + JOB_DEATH_KNIGHT, + JOB_DARK_COLLECTOR, + + JOB_RUNE_KNIGHT = 4054, + JOB_WARLOCK, + JOB_RANGER, + JOB_ARCH_BISHOP, + JOB_MECHANIC, + JOB_GUILLOTINE_CROSS, + + JOB_RUNE_KNIGHT_T, + JOB_WARLOCK_T, + JOB_RANGER_T, + JOB_ARCH_BISHOP_T, + JOB_MECHANIC_T, + JOB_GUILLOTINE_CROSS_T, + + JOB_ROYAL_GUARD, + JOB_SORCERER, + JOB_MINSTREL, + JOB_WANDERER, + JOB_SURA, + JOB_GENETIC, + JOB_SHADOW_CHASER, + + JOB_ROYAL_GUARD_T, + JOB_SORCERER_T, + JOB_MINSTREL_T, + JOB_WANDERER_T, + JOB_SURA_T, + JOB_GENETIC_T, + JOB_SHADOW_CHASER_T, + + JOB_RUNE_KNIGHT2, + JOB_RUNE_KNIGHT_T2, + JOB_ROYAL_GUARD2, + JOB_ROYAL_GUARD_T2, + JOB_RANGER2, + JOB_RANGER_T2, + JOB_MECHANIC2, + JOB_MECHANIC_T2, + + JOB_BABY_RUNE = 4096, + JOB_BABY_WARLOCK, + JOB_BABY_RANGER, + JOB_BABY_BISHOP, + JOB_BABY_MECHANIC, + JOB_BABY_CROSS, + + JOB_BABY_GUARD, + JOB_BABY_SORCERER, + JOB_BABY_MINSTREL, + JOB_BABY_WANDERER, + JOB_BABY_SURA, + JOB_BABY_GENETIC, + JOB_BABY_CHASER, + + JOB_BABY_RUNE2, + JOB_BABY_GUARD2, + JOB_BABY_RANGER2, + JOB_BABY_MECHANIC2, + + JOB_SUPER_NOVICE_E = 4190, + JOB_SUPER_BABY_E, + + JOB_KAGEROU = 4211, + JOB_OBORO, + + JOB_MAX, }; enum { - SEX_FEMALE = 0, - SEX_MALE, - SEX_SERVER + SEX_FEMALE = 0, + SEX_MALE, + SEX_SERVER }; // sanity checks... diff --git a/src/common/mutex.c b/src/common/mutex.c index 6b4f55119..813bef31b 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -15,26 +15,26 @@ #include "../common/timer.h" #include "../common/mutex.h" -struct ramutex{ +struct ramutex { #ifdef WIN32 - CRITICAL_SECTION hMutex; + CRITICAL_SECTION hMutex; #else - pthread_mutex_t hMutex; + pthread_mutex_t hMutex; #endif }; -struct racond{ +struct racond { #ifdef WIN32 - HANDLE events[2]; - ra_align(8) volatile LONG nWaiters; - CRITICAL_SECTION waiters_lock; + HANDLE events[2]; + ra_align(8) volatile LONG nWaiters; + CRITICAL_SECTION waiters_lock; #define EVENT_COND_SIGNAL 0 #define EVENT_COND_BROADCAST 1 #else - pthread_cond_t hCond; + pthread_cond_t hCond; #endif }; @@ -46,68 +46,73 @@ struct racond{ // -ramutex ramutex_create(){ - struct ramutex *m; - - m = (struct ramutex*)aMalloc( sizeof(struct ramutex) ); - if(m == NULL){ - ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); - return NULL; - } - +ramutex ramutex_create() +{ + struct ramutex *m; + + m = (struct ramutex *)aMalloc(sizeof(struct ramutex)); + if (m == NULL) { + ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); + return NULL; + } + #ifdef WIN32 - InitializeCriticalSection(&m->hMutex); + InitializeCriticalSection(&m->hMutex); #else - pthread_mutex_init(&m->hMutex, NULL); + pthread_mutex_init(&m->hMutex, NULL); #endif - - return m; + + return m; }//end: ramutex_create() -void ramutex_destroy( ramutex m ){ +void ramutex_destroy(ramutex m) +{ #ifdef WIN32 - DeleteCriticalSection(&m->hMutex); + DeleteCriticalSection(&m->hMutex); #else - pthread_mutex_destroy(&m->hMutex); + pthread_mutex_destroy(&m->hMutex); #endif - aFree(m); + aFree(m); }//end: ramutex_destroy() -void ramutex_lock( ramutex m ){ +void ramutex_lock(ramutex m) +{ #ifdef WIN32 - EnterCriticalSection(&m->hMutex); + EnterCriticalSection(&m->hMutex); #else - pthread_mutex_lock(&m->hMutex); + pthread_mutex_lock(&m->hMutex); #endif }//end: ramutex_lock -bool ramutex_trylock( ramutex m ){ +bool ramutex_trylock(ramutex m) +{ #ifdef WIN32 - if(TryEnterCriticalSection(&m->hMutex) == TRUE) - return true; + if (TryEnterCriticalSection(&m->hMutex) == TRUE) + return true; - return false; + return false; #else - if(pthread_mutex_trylock(&m->hMutex) == 0) - return true; - - return false; + if (pthread_mutex_trylock(&m->hMutex) == 0) + return true; + + return false; #endif }//end: ramutex_trylock() -void ramutex_unlock( ramutex m ){ +void ramutex_unlock(ramutex m) +{ #ifdef WIN32 - LeaveCriticalSection(&m->hMutex); + LeaveCriticalSection(&m->hMutex); #else - pthread_mutex_unlock(&m->hMutex); + pthread_mutex_unlock(&m->hMutex); #endif }//end: ramutex_unlock() @@ -116,131 +121,136 @@ void ramutex_unlock( ramutex m ){ /////////////// // Condition Variables -// +// // Implementation: // -racond racond_create(){ - struct racond *c; - - c = (struct racond*)aMalloc( sizeof(struct racond) ); - if(c == NULL){ - ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); - return NULL; - } +racond racond_create() +{ + struct racond *c; + + c = (struct racond *)aMalloc(sizeof(struct racond)); + if (c == NULL) { + ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); + return NULL; + } #ifdef WIN32 - c->nWaiters = 0; - c->events[ EVENT_COND_SIGNAL ] = CreateEvent( NULL, FALSE, FALSE, NULL ); - c->events[ EVENT_COND_BROADCAST ] = CreateEvent( NULL, TRUE, FALSE, NULL ); - InitializeCriticalSection( &c->waiters_lock ); + c->nWaiters = 0; + c->events[ EVENT_COND_SIGNAL ] = CreateEvent(NULL, FALSE, FALSE, NULL); + c->events[ EVENT_COND_BROADCAST ] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&c->waiters_lock); #else - pthread_cond_init(&c->hCond, NULL); + pthread_cond_init(&c->hCond, NULL); #endif - - return c; + + return c; }//end: racond_create() -void racond_destroy( racond c ){ +void racond_destroy(racond c) +{ #ifdef WIN32 - CloseHandle( c->events[ EVENT_COND_SIGNAL ] ); - CloseHandle( c->events[ EVENT_COND_BROADCAST ] ); - DeleteCriticalSection( &c->waiters_lock ); + CloseHandle(c->events[ EVENT_COND_SIGNAL ]); + CloseHandle(c->events[ EVENT_COND_BROADCAST ]); + DeleteCriticalSection(&c->waiters_lock); #else - pthread_cond_destroy(&c->hCond); + pthread_cond_destroy(&c->hCond); #endif - aFree(c); + aFree(c); }//end: racond_destroy() -void racond_wait( racond c, ramutex m, sysint timeout_ticks){ +void racond_wait(racond c, ramutex m, sysint timeout_ticks) +{ #ifdef WIN32 - register DWORD ms; - int result; - bool is_last = false; + register DWORD ms; + int result; + bool is_last = false; - EnterCriticalSection(&c->waiters_lock); - c->nWaiters++; - LeaveCriticalSection(&c->waiters_lock); + EnterCriticalSection(&c->waiters_lock); + c->nWaiters++; + LeaveCriticalSection(&c->waiters_lock); - if(timeout_ticks < 0) - ms = INFINITE; - else - ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; - - - // we can release the mutex (m) here, cause win's - // manual reset events maintain state when used with - // SetEvent() - ramutex_unlock(m); + if (timeout_ticks < 0) + ms = INFINITE; + else + ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; - result = WaitForMultipleObjects(2, c->events, FALSE, ms); - - - EnterCriticalSection(&c->waiters_lock); - c->nWaiters--; - if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) ) - is_last = true; // Broadcast called! - LeaveCriticalSection(&c->waiters_lock); - + // we can release the mutex (m) here, cause win's + // manual reset events maintain state when used with + // SetEvent() + ramutex_unlock(m); - // we are the last waiter that has to be notified, or to stop waiting - // so we have to do a manual reset - if(is_last == true) - ResetEvent( c->events[EVENT_COND_BROADCAST] ); + result = WaitForMultipleObjects(2, c->events, FALSE, ms); - ramutex_lock(m); + EnterCriticalSection(&c->waiters_lock); + c->nWaiters--; + if ((result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0)) + is_last = true; // Broadcast called! + LeaveCriticalSection(&c->waiters_lock); + + + + // we are the last waiter that has to be notified, or to stop waiting + // so we have to do a manual reset + if (is_last == true) + ResetEvent(c->events[EVENT_COND_BROADCAST]); + + + ramutex_lock(m); #else - if(timeout_ticks < 0){ - pthread_cond_wait( &c->hCond, &m->hMutex ); - }else{ - struct timespec wtime; - int64 exact_timeout = gettick() + timeout_ticks; - - wtime.tv_sec = exact_timeout/1000; - wtime.tv_nsec = (exact_timeout%1000)*1000000; - - pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime); - } + if (timeout_ticks < 0) { + pthread_cond_wait(&c->hCond, &m->hMutex); + } else { + struct timespec wtime; + int64 exact_timeout = gettick() + timeout_ticks; + + wtime.tv_sec = exact_timeout/1000; + wtime.tv_nsec = (exact_timeout%1000)*1000000; + + pthread_cond_timedwait(&c->hCond, &m->hMutex, &wtime); + } #endif }//end: racond_wait() -void racond_signal( racond c ){ +void racond_signal(racond c) +{ #ifdef WIN32 -// bool has_waiters = false; -// EnterCriticalSection(&c->waiters_lock); -// if(c->nWaiters > 0) -// has_waiters = true; -// LeaveCriticalSection(&c->waiters_lock); - -// if(has_waiters == true) - SetEvent( c->events[ EVENT_COND_SIGNAL ] ); + // bool has_waiters = false; + // EnterCriticalSection(&c->waiters_lock); + // if(c->nWaiters > 0) + // has_waiters = true; + // LeaveCriticalSection(&c->waiters_lock); + + // if(has_waiters == true) + SetEvent(c->events[ EVENT_COND_SIGNAL ]); #else - pthread_cond_signal(&c->hCond); + pthread_cond_signal(&c->hCond); #endif }//end: racond_signal() -void racond_broadcast( racond c ){ +void racond_broadcast(racond c) +{ #ifdef WIN32 -// bool has_waiters = false; -// EnterCriticalSection(&c->waiters_lock); -// if(c->nWaiters > 0) -// has_waiters = true; -// LeaveCriticalSection(&c->waiters_lock); - -// if(has_waiters == true) - SetEvent( c->events[ EVENT_COND_BROADCAST ] ); + // bool has_waiters = false; + // EnterCriticalSection(&c->waiters_lock); + // if(c->nWaiters > 0) + // has_waiters = true; + // LeaveCriticalSection(&c->waiters_lock); + + // if(has_waiters == true) + SetEvent(c->events[ EVENT_COND_BROADCAST ]); #else - pthread_cond_broadcast(&c->hCond); + pthread_cond_broadcast(&c->hCond); #endif }//end: racond_broadcast() diff --git a/src/common/mutex.h b/src/common/mutex.h index 1999627cd..abef731f4 100644 --- a/src/common/mutex.h +++ b/src/common/mutex.h @@ -1,5 +1,5 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// For more information, see LICENCE in the main folder #ifndef _rA_MUTEX_H_ #define _rA_MUTEX_H_ @@ -9,67 +9,67 @@ typedef struct ramutex *ramutex; // Mutex typedef struct racond *racond; // Condition Var /** - * Creates a Mutex + * Creates a Mutex * * @return not NULL */ ramutex ramutex_create(); -/** +/** * Destroys a Mutex - * + * * @param m - the mutex to destroy */ -void ramutex_destroy( ramutex m ); +void ramutex_destroy(ramutex m); -/** +/** * Gets a lock * * @param m - the mutex to lock */ -void ramutex_lock( ramutex m); +void ramutex_lock(ramutex m); -/** +/** * Trys to get the Lock - * + * * @param m - the mutex try to lock - * + * * @return boolean (true = got the lock) */ -bool ramutex_trylock( ramutex m ); +bool ramutex_trylock(ramutex m); -/** +/** * Unlocks a mutex * * @param m - the mutex to unlock */ -void ramutex_unlock( ramutex m); +void ramutex_unlock(ramutex m); -/** +/** * Creates a Condition variable * * @return not NULL */ racond racond_create(); -/** +/** * Destroy a Condition variable * * @param c - the condition varaible to destroy */ -void racond_destroy( racond c ); +void racond_destroy(racond c); /** * Waits Until state is signalled - * - * @param c - the condition var to wait for signalled state + * + * @param c - the condition var to wait for signalled state * @param m - the mutex used for syncronization * @param timeout_ticks - timeout in ticks ( -1 = INFINITE ) */ -void racond_wait( racond c, ramutex m, sysint timeout_ticks); +void racond_wait(racond c, ramutex m, sysint timeout_ticks); -/** +/** * Sets the given condition var to signalled state * * @param c - condition var to set in signalled state. @@ -77,16 +77,16 @@ void racond_wait( racond c, ramutex m, sysint timeout_ticks); * @note: * Only one waiter gets notified. */ -void racond_signal( racond c ); +void racond_signal(racond c); -/** +/** * Sets notifys all waiting threads thats signalled. * @param c - condition var to set in signalled state - * + * * @note: * All Waiters getting notified. - */ -void racond_broadcast( racond c ); + */ +void racond_broadcast(racond c); #endif diff --git a/src/common/netbuffer.c b/src/common/netbuffer.c index 57742d612..9ce13ffc3 100644 --- a/src/common/netbuffer.c +++ b/src/common/netbuffer.c @@ -26,10 +26,10 @@ #include "../common/netbuffer.h" -// +// // Buffers are available in the following sizes: -// 48, 192, 2048, 8192 -// 65536 (inter server connects may use it for charstatus struct..) +// 48, 192, 2048, 8192 +// 65536 (inter server connects may use it for charstatus struct..) // @@ -42,180 +42,197 @@ static sysint *l_poolElemSize = NULL; static mempool *l_pool = NULL; -void netbuffer_init(){ - char localsection[32]; - raconf conf; - sysint i; - - // Initialize Statistic counters: - l_nEmergencyAllocations = 0; - - // Set localsection name according to running serverype. - switch(SERVER_TYPE){ - case ATHENA_SERVER_LOGIN: strcpy(localsection, "login-netbuffer"); break; - case ATHENA_SERVER_CHAR: strcpy(localsection, "char-netbuffer"); break; - case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; - case ATHENA_SERVER_MAP: strcpy(localsection, "map-netbuffer"); break; - default: strcpy(localsection, "unsupported_type"); break; - } - - - conf = raconf_parse("conf/network.conf"); - if(conf == NULL){ - ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); - exit(EXIT_FAILURE); - } - - // Get Values from config file - l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); - if(l_nPools == 0){ - ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); - exit(EXIT_FAILURE); - } - - // Allocate arrays. - l_poolElemSize = (sysint*)aCalloc( l_nPools, sizeof(sysint) ); - l_pool = (mempool*)aCalloc( l_nPools, sizeof(mempool) ); - - - for(i = 0; i < l_nPools; i++){ - int64 num_prealloc, num_realloc; - char key[32]; - - sprintf(key, "pool_%u_size", (uint32)i+1); - l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); - if(l_poolElemSize[i] < 32){ - ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); - l_poolElemSize[i] = 32; - } - - sprintf(key, "pool_%u_prealloc", (uint32)i+1); - num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); - - sprintf(key, "pool_%u_realloc_step", (uint32)i+1); - num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); - - // Create Pool! - sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. - - // Info - ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); - - // - // Size Calculation: - // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) - l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); - if(l_pool[i] == NULL){ - ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); - // @leak: clean everything :D - exit(EXIT_FAILURE); - } - - }// - - - raconf_destroy(conf); +void netbuffer_init() +{ + char localsection[32]; + raconf conf; + sysint i; + + // Initialize Statistic counters: + l_nEmergencyAllocations = 0; + + // Set localsection name according to running serverype. + switch (SERVER_TYPE) { + case ATHENA_SERVER_LOGIN: + strcpy(localsection, "login-netbuffer"); + break; + case ATHENA_SERVER_CHAR: + strcpy(localsection, "char-netbuffer"); + break; + case ATHENA_SERVER_INTER: + strcpy(localsection, "inter-netbuffer"); + break; + case ATHENA_SERVER_MAP: + strcpy(localsection, "map-netbuffer"); + break; + default: + strcpy(localsection, "unsupported_type"); + break; + } + + + conf = raconf_parse("conf/network.conf"); + if (conf == NULL) { + ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); + exit(EXIT_FAILURE); + } + + // Get Values from config file + l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); + if (l_nPools == 0) { + ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); + exit(EXIT_FAILURE); + } + + // Allocate arrays. + l_poolElemSize = (sysint *)aCalloc(l_nPools, sizeof(sysint)); + l_pool = (mempool *)aCalloc(l_nPools, sizeof(mempool)); + + + for (i = 0; i < l_nPools; i++) { + int64 num_prealloc, num_realloc; + char key[32]; + + sprintf(key, "pool_%u_size", (uint32)i+1); + l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); + if (l_poolElemSize[i] < 32) { + ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); + l_poolElemSize[i] = 32; + } + + sprintf(key, "pool_%u_prealloc", (uint32)i+1); + num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); + + sprintf(key, "pool_%u_realloc_step", (uint32)i+1); + num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); + + // Create Pool! + sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. + + // Info + ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); + + // + // Size Calculation: + // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) + l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); + if (l_pool[i] == NULL) { + ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); + // @leak: clean everything :D + exit(EXIT_FAILURE); + } + + }// + + + raconf_destroy(conf); }//end: netbuffer_init() -void netbuffer_final(){ - sysint i; - - if(l_nPools > 0){ - /// .. finalize mempools - for(i = 0; i < l_nPools; i++){ - mempool_stats stats = mempool_get_stats(l_pool[i]); - - ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); - - mempool_destroy(l_pool[i]); - } - - if(l_nEmergencyAllocations > 0){ - ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); - l_nEmergencyAllocations = 0; - } - - aFree(l_poolElemSize); l_poolElemSize = NULL; - aFree(l_pool); l_pool = NULL; - l_nPools = 0; - } - - +void netbuffer_final() +{ + sysint i; + + if (l_nPools > 0) { + /// .. finalize mempools + for (i = 0; i < l_nPools; i++) { + mempool_stats stats = mempool_get_stats(l_pool[i]); + + ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); + + mempool_destroy(l_pool[i]); + } + + if (l_nEmergencyAllocations > 0) { + ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); + l_nEmergencyAllocations = 0; + } + + aFree(l_poolElemSize); + l_poolElemSize = NULL; + aFree(l_pool); + l_pool = NULL; + l_nPools = 0; + } + + }//end: netbuffer_final() -netbuf netbuffer_get( sysint sz ){ - sysint i; - netbuf nb = NULL; - - // Search an appropriate pool - for(i = 0; i < l_nPools; i++){ - if(sz <= l_poolElemSize[i]){ - // match - - nb = (netbuf)mempool_node_get(l_pool[i]); - nb->pool = i; - - break; - } - } - - // No Bufferpool found that mets there quirements?.. (thats bad..) - if(nb == NULL){ - ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); - ShowWarning("Please reconfigure your network.conf!"); - - InterlockedIncrement(&l_nEmergencyAllocations); - - // .. better to check (netbuf struct provides 32 byte bufferspace itself. - if(sz < 32) sz = 32; - - // allocate memory using malloc .. - while(1){ - nb = (netbuf) aMalloc( (sizeof(struct netbuf) + sz - 32) ); - if(nb != NULL){ - memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32) ); // zero memory! (to enforce commit @ os.) - nb->pool = -1; // emergency alloc. - break; - } - - rathread_yield(); - }// spin allocation. - - } - - - nb->refcnt = 1; // Initial refcount is 1 - - return nb; +netbuf netbuffer_get(sysint sz) +{ + sysint i; + netbuf nb = NULL; + + // Search an appropriate pool + for (i = 0; i < l_nPools; i++) { + if (sz <= l_poolElemSize[i]) { + // match + + nb = (netbuf)mempool_node_get(l_pool[i]); + nb->pool = i; + + break; + } + } + + // No Bufferpool found that mets there quirements?.. (thats bad..) + if (nb == NULL) { + ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); + ShowWarning("Please reconfigure your network.conf!"); + + InterlockedIncrement(&l_nEmergencyAllocations); + + // .. better to check (netbuf struct provides 32 byte bufferspace itself. + if (sz < 32) sz = 32; + + // allocate memory using malloc .. + while (1) { + nb = (netbuf) aMalloc((sizeof(struct netbuf) + sz - 32)); + if (nb != NULL) { + memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32)); // zero memory! (to enforce commit @ os.) + nb->pool = -1; // emergency alloc. + break; + } + + rathread_yield(); + }// spin allocation. + + } + + + nb->refcnt = 1; // Initial refcount is 1 + + return nb; }//end: netbuffer_get() -void netbuffer_put( netbuf nb ){ - - // Decrement reference counter, if > 0 do nothing :) - if( InterlockedDecrement(&nb->refcnt) > 0 ) - return; - - // Is this buffer an emergency allocated buffer? - if(nb->pool == -1){ - aFree(nb); - return; - } - - - // Otherwise its a normal mempool based buffer - // return it to the according mempool: - mempool_node_put( l_pool[nb->pool], nb); - - +void netbuffer_put(netbuf nb) +{ + + // Decrement reference counter, if > 0 do nothing :) + if (InterlockedDecrement(&nb->refcnt) > 0) + return; + + // Is this buffer an emergency allocated buffer? + if (nb->pool == -1) { + aFree(nb); + return; + } + + + // Otherwise its a normal mempool based buffer + // return it to the according mempool: + mempool_node_put(l_pool[nb->pool], nb); + + }//end: netbuffer_put() -void netbuffer_incref( netbuf nb ){ - - InterlockedIncrement(&nb->refcnt); - +void netbuffer_incref(netbuf nb) +{ + + InterlockedIncrement(&nb->refcnt); + }//end: netbuf_incref() diff --git a/src/common/netbuffer.h b/src/common/netbuffer.h index 844241226..a4feb7287 100644 --- a/src/common/netbuffer.h +++ b/src/common/netbuffer.h @@ -6,37 +6,37 @@ #include "../common/cbasetypes.h" -typedef struct netbuf{ - sysint pool; // The pool ID this buffer belongs to, - // is set to -1 if its an emergency allocated buffer - - struct netbuf *next; // Used by Network system. - - volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, - // if its getting zero, the buffer will returned back to the pool - // and can be reused. - - int32 dataPos; // Current Offset - // Used only for Reading (recv job) - // write cases are using the sessions local datapos member due to - // shared write buffer support. - - int32 dataLen; // read buffer case: - // The length expected to read to. - // when this->dataPos == dateLen, read job has been completed. - // write buffer case: - // The lngth of data in te buffer - // when s->dataPos == dataLen, write job has been completed - // - // Note: - // leftBytes = (dateLen - dataPos) - // - // Due to shared buffer support - // dataPos gets not used in write case (each connection has its local offset) - // - - // The Bufferspace itself. - char buf[32]; +typedef struct netbuf { + sysint pool; // The pool ID this buffer belongs to, + // is set to -1 if its an emergency allocated buffer + + struct netbuf *next; // Used by Network system. + + volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, + // if its getting zero, the buffer will returned back to the pool + // and can be reused. + + int32 dataPos; // Current Offset + // Used only for Reading (recv job) + // write cases are using the sessions local datapos member due to + // shared write buffer support. + + int32 dataLen; // read buffer case: + // The length expected to read to. + // when this->dataPos == dateLen, read job has been completed. + // write buffer case: + // The lngth of data in te buffer + // when s->dataPos == dataLen, write job has been completed + // + // Note: + // leftBytes = (dateLen - dataPos) + // + // Due to shared buffer support + // dataPos gets not used in write case (each connection has its local offset) + // + + // The Bufferspace itself. + char buf[32]; } *netbuf; @@ -47,29 +47,29 @@ void netbuffer_final(); * Gets a netbuffer that has atleast (sz) byes space. * * @note: The netbuffer system guarantees that youll always recevie a buffer. - * no check for null is required! + * no check for null is required! * * @param sz - minimum size needed. * * @return pointer to netbuf struct */ -netbuf netbuffer_get( sysint sz ); +netbuf netbuffer_get(sysint sz); -/** +/** * Returns the given netbuffer (decreases refcount, if its 0 - the buffer will get returned to the pool) * - * @param buf - the buffer to return + * @param buf - the buffer to return */ -void netbuffer_put( netbuf buf ); +void netbuffer_put(netbuf buf); -/** - * Increases the Refcount on the given buffer +/** + * Increases the Refcount on the given buffer * (used for areasends .. etc) * */ -void netbuffer_incref( netbuf buf ); +void netbuffer_incref(netbuf buf); // Some Useful macros diff --git a/src/common/network.c b/src/common/network.c index 1f1621363..1c968200d 100644 --- a/src/common/network.c +++ b/src/common/network.c @@ -51,1011 +51,1020 @@ static bool onSend(int32 fd); #define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t) buf) -static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data){ - // netbuf is in data - netbuffer_put( (netbuf)data ); +static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data) +{ + // netbuf is in data + netbuffer_put((netbuf)data); - return 0; + return 0; }//end: _network_async_free_netbuf_proc() -void network_init(){ - SESSION *s; - int32 i; - - memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN) ); - - for(i = 0; i < MAXCONN; i++){ - s = &g_Session[i]; - - s->type = NST_FREE; - s->disconnect_in_progress = false; - - } - - // Initialize the correspondig event dispatcher - evdp_init(); - - // - add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); - +void network_init() +{ + SESSION *s; + int32 i; + + memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN)); + + for (i = 0; i < MAXCONN; i++) { + s = &g_Session[i]; + + s->type = NST_FREE; + s->disconnect_in_progress = false; + + } + + // Initialize the correspondig event dispatcher + evdp_init(); + + // + add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); + }//end: network_init() -void network_final(){ +void network_final() +{ + + // @TODO: + // .. disconnect and cleanup everything! - // @TODO: - // .. disconnect and cleanup everything! - - evdp_final(); + evdp_final(); }//end: network_final() -void network_do(){ - struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; - register struct EVDP_EVENT *ev; - register int n, nfds; - register SESSION *s; - - nfds = evdp_wait( l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() - - for(n = 0; n < nfds; n++){ - ev = &l_events[n]; - s = &g_Session[ ev->fd ]; - - if(ev->events & EVDP_EVENT_HUP){ - network_disconnect( ev->fd ); - continue; // no further event processing. - }// endif vent is HUP (disconnect) - - - if(ev->events & EVDP_EVENT_IN){ - - if(s->onRecv != NULL){ - if( false == s->onRecv(ev->fd) ){ - network_disconnect(ev->fd); - continue; // .. - } - }else{ - ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - - }// endif event is IN (recv) - - - if(ev->events & EVDP_EVENT_OUT){ - if(s->onSend != NULL){ - if( false == s->onSend(ev->fd) ){ - network_disconnect(ev->fd); - continue; - } - }else{ - ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - }// endif event is OUT (send) - - }//endfor - +void network_do() +{ + struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; + register struct EVDP_EVENT *ev; + register int n, nfds; + register SESSION *s; + + nfds = evdp_wait(l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() + + for (n = 0; n < nfds; n++) { + ev = &l_events[n]; + s = &g_Session[ ev->fd ]; + + if (ev->events & EVDP_EVENT_HUP) { + network_disconnect(ev->fd); + continue; // no further event processing. + }// endif vent is HUP (disconnect) + + + if (ev->events & EVDP_EVENT_IN) { + + if (s->onRecv != NULL) { + if (false == s->onRecv(ev->fd)) { + network_disconnect(ev->fd); + continue; // .. + } + } else { + ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + + }// endif event is IN (recv) + + + if (ev->events & EVDP_EVENT_OUT) { + if (s->onSend != NULL) { + if (false == s->onSend(ev->fd)) { + network_disconnect(ev->fd); + continue; + } + } else { + ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + }// endif event is OUT (send) + + }//endfor + }//end: network_do() -static bool _setnonblock(int32 fd){ - int flags = fcntl(fd, F_GETFL, 0); - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) - return false; +static bool _setnonblock(int32 fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) + return false; - return true; + return true; }//end: _setnonblock() -static bool _network_accept(int32 fd){ - SESSION *listener = &g_Session[fd]; - SESSION *s; - union{ - struct sockaddr_in v4; +static bool _network_accept(int32 fd) +{ + SESSION *listener = &g_Session[fd]; + SESSION *s; + union { + struct sockaddr_in v4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 v6; + struct sockaddr_in6 v6; #endif - } _addr; - int newfd; - socklen_t addrlen; - struct sockaddr *addr; - - // Accept until OS returns - nothing to accept anymore - // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) - while(1){ + } _addr; + int newfd; + socklen_t addrlen; + struct sockaddr *addr; + + // Accept until OS returns - nothing to accept anymore + // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) + while (1) { #ifdef ENABLE_IPV6 - if(listener->v6 == true){ - addrlen = sizeof(_addr.v6); - addr = (struct sockaddr*)&_addr.v6; - }else{ + if (listener->v6 == true) { + addrlen = sizeof(_addr.v6); + addr = (struct sockaddr *)&_addr.v6; + } else { #endif - addrlen = sizeof(_addr.v4); - addr = (struct sockaddr*)&_addr.v4; + addrlen = sizeof(_addr.v4); + addr = (struct sockaddr *)&_addr.v4; #ifdef ENABLE_IPV6 - } + } #endif #ifdef HAVE_ACCEPT4 - newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); + newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); #else - newfd = accept(fd, addr, &addrlen); + newfd = accept(fd, addr, &addrlen); #endif - if(newfd == -1){ - if(errno == EAGAIN || errno == EWOULDBLOCK) - break; // this is fully valid & whished., se explaination on top of while(1) - - // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. - // @TODO handle this .. - ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); + if (newfd == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; // this is fully valid & whished., se explaination on top of while(1) + + // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. + // @TODO handle this .. + ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); - return false; // will call disconnect after return. - //break; - } + return false; // will call disconnect after return. + //break; + } #ifndef HAVE_ACCEPT4 // no accept4 means, we have to set nonblock by ourself. .. - if(_setnonblock(newfd) == false){ - ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); - close(newfd); - continue; - } + if (_setnonblock(newfd) == false) { + ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); + close(newfd); + continue; + } #endif - // Check connection limits. - if(newfd >= MAXCONN){ - ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); - close(newfd); - continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. - } - - - // Create new Session. - s = &g_Session[newfd]; - s->type = NST_CLIENT; - - // The new connection inherits listenr's handlers. - s->onDisconnect = listener->onDisconnect; - s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ - - // Register the new connection @ EVDP - if( evdp_addclient(newfd, &s->evdp_data) == false){ - ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); - close(newfd); - s->type = NST_FREE; - } - - // Call the onConnect handler on the listener. - if( listener->onConnect(newfd) == false ){ - // Resfused by onConnect handler.. - evdp_remove(newfd, &s->evdp_data); - - close(newfd); - s->type = NST_FREE; - - s->data = NULL; // be on the safe side ~ ! - continue; - } - - - } - - return true; + // Check connection limits. + if (newfd >= MAXCONN) { + ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); + close(newfd); + continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. + } + + + // Create new Session. + s = &g_Session[newfd]; + s->type = NST_CLIENT; + + // The new connection inherits listenr's handlers. + s->onDisconnect = listener->onDisconnect; + s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ + + // Register the new connection @ EVDP + if (evdp_addclient(newfd, &s->evdp_data) == false) { + ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); + close(newfd); + s->type = NST_FREE; + } + + // Call the onConnect handler on the listener. + if (listener->onConnect(newfd) == false) { + // Resfused by onConnect handler.. + evdp_remove(newfd, &s->evdp_data); + + close(newfd); + s->type = NST_FREE; + + s->data = NULL; // be on the safe side ~ ! + continue; + } + + + } + + return true; }//end: _network_accept() -void network_disconnect(int32 fd){ - SESSION *s = &g_Session[fd]; - netbuf b, bn; - - // Prevent recursive calls - // by wrong implemented on disconnect handlers.. and such.. - if(s->disconnect_in_progress == true) - return; - - s->disconnect_in_progress = true; - - - // Disconnect Todo: - // - Call onDisconnect Handler - // - Release all Assigned buffers. - // - remove from event system (notifications) - // - cleanup session structure - // - close connection. - // - - if(s->onDisconnect != NULL && - s->type != NST_LISTENER){ - - s->onDisconnect( fd ); - } - - // Read Buffer - if(s->read.buf != NULL){ - netbuffer_put(s->read.buf); - s->read.buf = NULL; - } - - // Write Buffer(s) - b = s->write.buf; - while(1){ - if(b == NULL) break; - - bn = b->next; - - netbuffer_put(b); - - b = bn; - } - s->write.buf = NULL; - s->write.buf_last = NULL; - - s->write.n_outstanding = 0; - s->write.max_outstanding = 0; - - - // Remove from event system. - evdp_remove(fd, &s->evdp_data); - - // Cleanup Session Structure. - s->type = NST_FREE; - s->data = NULL; // no application level data assigned - s->disconnect_in_progress = false; - - - // Close connection - close(fd); - +void network_disconnect(int32 fd) +{ + SESSION *s = &g_Session[fd]; + netbuf b, bn; + + // Prevent recursive calls + // by wrong implemented on disconnect handlers.. and such.. + if (s->disconnect_in_progress == true) + return; + + s->disconnect_in_progress = true; + + + // Disconnect Todo: + // - Call onDisconnect Handler + // - Release all Assigned buffers. + // - remove from event system (notifications) + // - cleanup session structure + // - close connection. + // + + if (s->onDisconnect != NULL && + s->type != NST_LISTENER) { + + s->onDisconnect(fd); + } + + // Read Buffer + if (s->read.buf != NULL) { + netbuffer_put(s->read.buf); + s->read.buf = NULL; + } + + // Write Buffer(s) + b = s->write.buf; + while (1) { + if (b == NULL) break; + + bn = b->next; + + netbuffer_put(b); + + b = bn; + } + s->write.buf = NULL; + s->write.buf_last = NULL; + + s->write.n_outstanding = 0; + s->write.max_outstanding = 0; + + + // Remove from event system. + evdp_remove(fd, &s->evdp_data); + + // Cleanup Session Structure. + s->type = NST_FREE; + s->data = NULL; // no application level data assigned + s->disconnect_in_progress = false; + + + // Close connection + close(fd); + }//end: network_disconnect() -int32 network_addlistener(bool v6, const char *addr, uint16 port){ - SESSION *s; - int optval, fd; +int32 network_addlistener(bool v6, const char *addr, uint16 port) +{ + SESSION *s; + int optval, fd; #if !defined(ENABLE_IPV6) - if(v6 == true){ - ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + if (v6 == true) { + ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif #ifdef ENABLE_IPV6 - if(v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if (v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); - - // Error? - if(fd == -1){ - ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - return -1; - } - - // Too many connections? - if(fd >= MAXCONN){ - ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); - close(fd); - return -1; - } - - - s = &g_Session[fd]; - if(s->type != NST_FREE){ // additional checks.. :) - ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); - close(fd); - return -1; - } - - - // Fill ip addr structs + fd = socket(AF_INET, SOCK_STREAM, 0); + + // Error? + if (fd == -1) { + ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + return -1; + } + + // Too many connections? + if (fd >= MAXCONN) { + ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); + close(fd); + return -1; + } + + + s = &g_Session[fd]; + if (s->type != NST_FREE) { // additional checks.. :) + ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); + close(fd); + return -1; + } + + + // Fill ip addr structs #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); - s->addr.v6.sin6_family = AF_INET6; - s->addr.v6.sin6_port = htons(port); - if(inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1){ - ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - }else{ + if (v6 == true) { + memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); + s->addr.v6.sin6_family = AF_INET6; + s->addr.v6.sin6_port = htons(port); + if (inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1) { + ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + } else { #endif - memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); - s->addr.v4.sin_family = AF_INET; - s->addr.v4.sin_port = htons(port); - s->addr.v4.sin_addr.s_addr = inet_addr(addr); + memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); + s->addr.v4.sin_family = AF_INET; + s->addr.v4.sin_port = htons(port); + s->addr.v4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif - - // if OS has support for SO_REUSEADDR, apply the flag - // so the address could be used when there're still time_wait sockets outstanding from previous application run. + + // if OS has support for SO_REUSEADDR, apply the flag + // so the address could be used when there're still time_wait sockets outstanding from previous application run. #ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif - // Bind + // Bind #ifdef ENABLE_IPV6 - if(v6 == true){ - if( bind(fd, (struct sockaddr*)&s->addr.v6, sizeof(s->addr.v6)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - }else{ + if (v6 == true) { + if (bind(fd, (struct sockaddr *)&s->addr.v6, sizeof(s->addr.v6)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + } else { #endif - if( bind(fd, (struct sockaddr*)&s->addr.v4, sizeof(s->addr.v4)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } + if (bind(fd, (struct sockaddr *)&s->addr.v4, sizeof(s->addr.v4)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - } + } #endif - if( listen(fd, l_ListenBacklog) == -1){ - ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Set to nonblock! - if(_setnonblock(fd) == false){ - ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Rgister @ evdp. - if( evdp_addlistener(fd, &s->evdp_data) != true){ - ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - - // Apply flags on Session array for this conneciton. - if(v6 == true) s->v6 = true; - else s->v6 = false; - - s->type = NST_LISTENER; - s->onRecv = _network_accept; - - ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)") ); - - return fd; + if (listen(fd, l_ListenBacklog) == -1) { + ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Set to nonblock! + if (_setnonblock(fd) == false) { + ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Rgister @ evdp. + if (evdp_addlistener(fd, &s->evdp_data) != true) { + ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + + // Apply flags on Session array for this conneciton. + if (v6 == true) s->v6 = true; + else s->v6 = false; + + s->type = NST_LISTENER; + s->onRecv = _network_accept; + + ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)")); + + return fd; }//end: network_addlistener() -static bool _network_connect_establishedHandler(int32 fd){ - register SESSION *s = &g_Session[fd]; - int val; - socklen_t val_len; - - if(s->type == NST_FREE) - return true; // due to multiple non coalesced event notifications - // this can happen .. when a previous handled event has already disconnected the connection - // within the same cycle.. - - val = -1; - val_len = sizeof(val); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); - - if(val != 0){ - // :( .. cleanup session.. - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we CANT return false, - // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. - }else{ - // ok - if(s->onConnect(fd) == false) { - // onConnect handler has refused the connection .. - // cleanup .. and ok - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. - } - - // connection established ! - // - if( evdp_outgoingconnection_established(fd, &s->evdp_data) == false ){ - return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. - } - - s->onSend = NULL; - - ShowStatus("#%u connection successfull!\n", fd); - } - - return true; +static bool _network_connect_establishedHandler(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + int val; + socklen_t val_len; + + if (s->type == NST_FREE) + return true; // due to multiple non coalesced event notifications + // this can happen .. when a previous handled event has already disconnected the connection + // within the same cycle.. + + val = -1; + val_len = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); + + if (val != 0) { + // :( .. cleanup session.. + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we CANT return false, + // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. + } else { + // ok + if (s->onConnect(fd) == false) { + // onConnect handler has refused the connection .. + // cleanup .. and ok + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. + } + + // connection established ! + // + if (evdp_outgoingconnection_established(fd, &s->evdp_data) == false) { + return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. + } + + s->onSend = NULL; + + ShowStatus("#%u connection successfull!\n", fd); + } + + return true; }//end: _network_connect_establishedHandler() int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) -){ - register SESSION *s; - int32 fd, optval, ret; - struct sockaddr_in ip4; + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) + ) +{ + register SESSION *s; + int32 fd, optval, ret; + struct sockaddr_in ip4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 ip6; + struct sockaddr_in6 ip6; #endif #ifdef ENABLE_IPV6 - if(v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if (v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, SOCK_STREAM, 0); #ifndef ENABLE_IPV6 - // check.. - if(v6 == true){ - ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + // check.. + if (v6 == true) { + ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif - // check connection limits. - if(fd >= MAXCONN){ - ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port ); - close(fd); - return -1; - } - - - // Originating IP/Port pair given ? - if(from_addr != NULL && *from_addr != 0){ - //.. - #ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - #endif - - #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(from_port); - - if(inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1){ - ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - ret = bind(fd, (struct sockaddr*)&ip6, sizeof(ip6)); - }else{ - #endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(from_port); - ip4.sin_addr.s_addr = inet_addr(from_addr); - ret = bind(fd, (struct sockaddr*)&ip4, sizeof(ip4)); - #ifdef ENABLE_IPV6 - } - #endif - - } - - - // Set non block - if(_setnonblock(fd) == false){ - ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Create ip addr block to connect to .. + // check connection limits. + if (fd >= MAXCONN) { + ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + + // Originating IP/Port pair given ? + if (from_addr != NULL && *from_addr != 0) { + //.. +#ifdef SO_REUSEADDR + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); +#endif + +#ifdef ENABLE_IPV6 + if (v6 == true) { + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(from_port); + + if (inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1) { + ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + ret = bind(fd, (struct sockaddr *)&ip6, sizeof(ip6)); + } else { +#endif + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(from_port); + ip4.sin_addr.s_addr = inet_addr(from_addr); + ret = bind(fd, (struct sockaddr *)&ip4, sizeof(ip4)); #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(port); - - if(inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1){ - ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - }else{ + } #endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(port); - ip4.sin_addr.s_addr = inet_addr(addr); + + } + + + // Set non block + if (_setnonblock(fd) == false) { + ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Create ip addr block to connect to .. +#ifdef ENABLE_IPV6 + if (v6 == true) { + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(port); + + if (inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1) { + ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + } else { +#endif + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(port); + ip4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif - // Assign Session.. - s = &g_Session[fd]; - s->type = NST_OUTGOING; - s->v6 = v6; - s->onConnect = onConnectionEstablishedHandler; - s->onDisconnect = onConnectionLooseHandler; - s->onRecv = NULL; - s->onSend = _network_connect_establishedHandler; + // Assign Session.. + s = &g_Session[fd]; + s->type = NST_OUTGOING; + s->v6 = v6; + s->onConnect = onConnectionEstablishedHandler; + s->onDisconnect = onConnectionLooseHandler; + s->onRecv = NULL; + s->onSend = _network_connect_establishedHandler; #ifdef ENABLE_IPV6 - if(v6 == true) - memcpy(&s->addr.v6, &ip6, sizeof(ip6)); - else + if (v6 == true) + memcpy(&s->addr.v6, &ip6, sizeof(ip6)); + else #endif - memcpy(&s->addr.v4, &ip4, sizeof(ip4)); - - // Register @ EVDP. as outgoing (see doc of the function) - if(evdp_addconnecting(fd, &s->evdp_data) == false){ - ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - - // cleanup session x.x.. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // close, return error code. - close(fd); - return -1; - } + memcpy(&s->addr.v4, &ip4, sizeof(ip4)); + + // Register @ EVDP. as outgoing (see doc of the function) + if (evdp_addconnecting(fd, &s->evdp_data) == false) { + ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + + // cleanup session x.x.. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // close, return error code. + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - if(v6 == true) - ret = connect(fd, (struct sockaddr*)&ip6, sizeof(ip6)); - else + if (v6 == true) + ret = connect(fd, (struct sockaddr *)&ip6, sizeof(ip6)); + else #endif - ret = connect(fd, (struct sockaddr*)&ip4, sizeof(ip4)); - - - // - if(ret != 0 && errno != EINPROGRESS){ - ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - - // Cleanup session .. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // .. remove from evdp and close fd. - evdp_remove(fd, &s->evdp_data); - close(fd); - return -1; - } - - - // ! The Info Message :~D - ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); - -return fd; + ret = connect(fd, (struct sockaddr *)&ip4, sizeof(ip4)); + + + // + if (ret != 0 && errno != EINPROGRESS) { + ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + + // Cleanup session .. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // .. remove from evdp and close fd. + evdp_remove(fd, &s->evdp_data); + close(fd); + return -1; + } + + + // ! The Info Message :~D + ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); + + return fd; }//end: network_connect() -static bool _onSend(int32 fd){ - register SESSION *s = &g_Session[fd]; - register netbuf buf, buf_next; - register uint32 szNeeded; - register int wLen; - - if(s->type == NST_FREE) - return true; // Possible due to multipl non coalsced event notifications - // so onSend gets called after disconnect caused by an previous vent. - // we can ignore the call to onSend, then. - - buf = s->write.buf; - while(1){ - if(buf == NULL) - break; - - buf_next = buf->next; - - - szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. - - // try to write. - wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); - if(wLen == 0){ - return false; // eof. - }else if(wLen == -1){ - if(errno == EAGAIN || errno == EWOULDBLOCK) - return true; // dont disconnect / try again later. - - // all other errors. . - return false; - } - - // Wrote data.. => - szNeeded -= wLen; - if(szNeeded > 0){ - // still data left .. - // - s->write.dataPos += wLen; // fix offset. - return true; - }else{ - // this buffer has been written successfully - // could be returned to pool. - netbuffer_put(buf); - s->write.n_outstanding--; // When threadsafe -> Interlocked here. - s->write.dataPos = 0; - } - - - buf = buf_next; - } - - // okay, - // reaching this part means: - // while interrupted by break - - // which means all buffers are written, nothing left - // - - s->write.buf_last = NULL; - s->write.buf = NULL; - s->write.n_outstanding = 0; - s->write.dataPos = 0; - - // Remove from event dispatcher (write notification) - // - evdp_writable_remove(fd, &s->evdp_data); - - return true; +static bool _onSend(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + register netbuf buf, buf_next; + register uint32 szNeeded; + register int wLen; + + if (s->type == NST_FREE) + return true; // Possible due to multipl non coalsced event notifications + // so onSend gets called after disconnect caused by an previous vent. + // we can ignore the call to onSend, then. + + buf = s->write.buf; + while (1) { + if (buf == NULL) + break; + + buf_next = buf->next; + + + szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. + + // try to write. + wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); + if (wLen == 0) { + return false; // eof. + } else if (wLen == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return true; // dont disconnect / try again later. + + // all other errors. . + return false; + } + + // Wrote data.. => + szNeeded -= wLen; + if (szNeeded > 0) { + // still data left .. + // + s->write.dataPos += wLen; // fix offset. + return true; + } else { + // this buffer has been written successfully + // could be returned to pool. + netbuffer_put(buf); + s->write.n_outstanding--; // When threadsafe -> Interlocked here. + s->write.dataPos = 0; + } + + + buf = buf_next; + } + + // okay, + // reaching this part means: + // while interrupted by break - + // which means all buffers are written, nothing left + // + + s->write.buf_last = NULL; + s->write.buf = NULL; + s->write.n_outstanding = 0; + s->write.dataPos = 0; + + // Remove from event dispatcher (write notification) + // + evdp_writable_remove(fd, &s->evdp_data); + + return true; }//end: _onSend() -static bool _onRORecv(int32 fd){ - register SESSION *s = &g_Session[fd]; - register uint32 szNeeded; - register char *p; - register int rLen; - - if(s->type == NST_FREE) - return true; // Possible due to multiple non coalesced events by evdp. - // simply ignore this call returning positive result. - - // Initialize p and szNeeded depending on change - // - switch(s->read.state){ - case NRS_WAITOP: - szNeeded = s->read.head_left; - p = ((char*)&s->read.head[0]) + (2-szNeeded); - break; - - case NRS_WAITLEN: - szNeeded = s->read.head_left; - p = ((char*)&s->read.head[1]) + (2-szNeeded); - break; - - case NRS_WAITDATA:{ - register netbuf buf = s->read.buf; - - szNeeded = (buf->dataLen - buf->dataPos); - p = (char*)&buf->buf[ buf->dataPos ]; - } - break; - - default: - // .. the impossible gets possible .. - ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - // - - rLen = read(fd, p, szNeeded); - if(rLen == 0){ - // eof.. - return false; - }else if(rLen == -1){ - - if(errno == EAGAIN || errno == EWOULDBLOCK){ - // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) - return true; - } - - // an additional interesting case would be - // EINTR, this 'could' be handled .. but: - // posix says that its possible that data gets currupted during irq - // or data gor read and not reported.., so we'd have a data loss.. - // (which shouldnt happen with stream based protocols such as tcp) - // its better to disonnect the client in that case. - - return false; - } - - // - // Got Data: - // next action also depends on current state .. - // - szNeeded -= rLen; - switch(s->read.state){ - case NRS_WAITOP: - - if(szNeeded > 0){ - // still data missing .. - s->read.head_left = szNeeded; - return true; // wait for completion. - }else{ - // complete .. - // next state depends on packet type. - - s->read.head[1] = ((uint16*)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] - - if(s->read.head[1] == ROPACKET_UNKNOWN){ - // unknown packet - disconnect - ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); - return false; - } - else if(s->read.head[1] == ROPACKET_DYNLEN){ - // dynamic length - // next state: requrie len. - s->read.state = NRS_WAITLEN; - s->read.head_left = 2; - return true; // - } - else if(s->read.head[1] == 2){ - // packet has no data (only opcode) - register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = 2; - buf->next = NULL; - - // Back to initial state -> Need opcode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine here. - s->onPacketComplete(fd, s->read.head[0], 2, buf); - - return true; // done :) - } - else{ - // paket needs .. data .. - register netbuf buf = netbuffer_get( s->read.head[1] ); - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach buffer. - s->read.buf = buf; - - // set state: - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (opcode read completed?) - - break; - - - case NRS_WAITLEN: - - if(szNeeded > 0){ - // incomplete .. - s->read.head_left = szNeeded; - return true; - }else{ - - if(s->read.head[1] == 4){ - // packet has no data (only opcode + length) - register netbuf buf = netbuffer_get( 4 ); - - NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = 4; - buf->next = NULL; - - // set initial state (need opcode) - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // call completion routine. - s->onPacketComplete(fd, s->read.head[0], 4, buf); - - return true; - } - else if(s->read.head[1] < 4){ - // invalid header. - ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); - return false; - } - else{ - // Data needed - // next state -> waitdata! - register netbuf buf = netbuffer_get( s->read.head[1] ); - - NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach to session: - s->read.buf = buf; - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (length read complete?) - - break; - - - case NRS_WAITDATA: - - if(szNeeded == 0){ - // Packet finished! - // compltion. - register netbuf buf = s->read.buf; - - // set initial state. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine. - s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); - - return true; - }else{ - // still data needed - s->read.buf->dataPos += rLen; - - return true; - } - break; - - - // - default: - ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - return false; +static bool _onRORecv(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + register uint32 szNeeded; + register char *p; + register int rLen; + + if (s->type == NST_FREE) + return true; // Possible due to multiple non coalesced events by evdp. + // simply ignore this call returning positive result. + + // Initialize p and szNeeded depending on change + // + switch (s->read.state) { + case NRS_WAITOP: + szNeeded = s->read.head_left; + p = ((char *)&s->read.head[0]) + (2-szNeeded); + break; + + case NRS_WAITLEN: + szNeeded = s->read.head_left; + p = ((char *)&s->read.head[1]) + (2-szNeeded); + break; + + case NRS_WAITDATA: { + register netbuf buf = s->read.buf; + + szNeeded = (buf->dataLen - buf->dataPos); + p = (char *)&buf->buf[ buf->dataPos ]; + } + break; + + default: + // .. the impossible gets possible .. + ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + // + + rLen = read(fd, p, szNeeded); + if (rLen == 0) { + // eof.. + return false; + } else if (rLen == -1) { + + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) + return true; + } + + // an additional interesting case would be + // EINTR, this 'could' be handled .. but: + // posix says that its possible that data gets currupted during irq + // or data gor read and not reported.., so we'd have a data loss.. + // (which shouldnt happen with stream based protocols such as tcp) + // its better to disonnect the client in that case. + + return false; + } + + // + // Got Data: + // next action also depends on current state .. + // + szNeeded -= rLen; + switch (s->read.state) { + case NRS_WAITOP: + + if (szNeeded > 0) { + // still data missing .. + s->read.head_left = szNeeded; + return true; // wait for completion. + } else { + // complete .. + // next state depends on packet type. + + s->read.head[1] = ((uint16 *)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] + + if (s->read.head[1] == ROPACKET_UNKNOWN) { + // unknown packet - disconnect + ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); + return false; + } else if (s->read.head[1] == ROPACKET_DYNLEN) { + // dynamic length + // next state: requrie len. + s->read.state = NRS_WAITLEN; + s->read.head_left = 2; + return true; // + } else if (s->read.head[1] == 2) { + // packet has no data (only opcode) + register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = 2; + buf->next = NULL; + + // Back to initial state -> Need opcode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine here. + s->onPacketComplete(fd, s->read.head[0], 2, buf); + + return true; // done :) + } else { + // paket needs .. data .. + register netbuf buf = netbuffer_get(s->read.head[1]); + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach buffer. + s->read.buf = buf; + + // set state: + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (opcode read completed?) + + break; + + + case NRS_WAITLEN: + + if (szNeeded > 0) { + // incomplete .. + s->read.head_left = szNeeded; + return true; + } else { + + if (s->read.head[1] == 4) { + // packet has no data (only opcode + length) + register netbuf buf = netbuffer_get(4); + + NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = 4; + buf->next = NULL; + + // set initial state (need opcode) + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // call completion routine. + s->onPacketComplete(fd, s->read.head[0], 4, buf); + + return true; + } else if (s->read.head[1] < 4) { + // invalid header. + ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); + return false; + } else { + // Data needed + // next state -> waitdata! + register netbuf buf = netbuffer_get(s->read.head[1]); + + NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach to session: + s->read.buf = buf; + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (length read complete?) + + break; + + + case NRS_WAITDATA: + + if (szNeeded == 0) { + // Packet finished! + // compltion. + register netbuf buf = s->read.buf; + + // set initial state. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine. + s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); + + return true; + } else { + // still data needed + s->read.buf->dataPos += rLen; + + return true; + } + break; + + + // + default: + ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + return false; }//end: _onRORecv() -void network_send(int32 fd, netbuf buf){ - register SESSION *s = &g_Session[fd]; - +void network_send(int32 fd, netbuf buf) +{ + register SESSION *s = &g_Session[fd]; + #ifdef PARANOID_CHECKS - if(fd >= MAXCONN){ - ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); - _network_free_netbuf_async(buf); - return; - } + if (fd >= MAXCONN) { + ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); + _network_free_netbuf_async(buf); + return; + } #endif - if(s->type == NST_FREE) - return; - - // Check Max Outstanding buffers limit. - if( (s->write.max_outstanding > 0) && - (s->write.n_outstanding >= s->write.max_outstanding) ){ - - ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); - network_disconnect(fd); - // - _network_free_netbuf_async(buf); - return; - } - - - // Attach to the end: - buf->next = NULL; - if(s->write.buf_last != NULL){ - s->write.buf_last->next = buf; - s->write.buf_last = buf; - - }else{ - // currently no buffer attached. - s->write.buf = s->write.buf_last = buf; - - // register @ evdp for writable notification. - evdp_writable_add(fd, &s->evdp_data); // - } - - - // - s->write.n_outstanding++; - + if (s->type == NST_FREE) + return; + + // Check Max Outstanding buffers limit. + if ((s->write.max_outstanding > 0) && + (s->write.n_outstanding >= s->write.max_outstanding)) { + + ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); + network_disconnect(fd); + // + _network_free_netbuf_async(buf); + return; + } + + + // Attach to the end: + buf->next = NULL; + if (s->write.buf_last != NULL) { + s->write.buf_last->next = buf; + s->write.buf_last = buf; + + } else { + // currently no buffer attached. + s->write.buf = s->write.buf_last = buf; + + // register @ evdp for writable notification. + evdp_writable_add(fd, &s->evdp_data); // + } + + + // + s->write.n_outstanding++; + }//end: network_send() void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ){ - register SESSION *s = &g_Session[fd]; - register netbuf b, nb; // used for potential free attached buffers. - - if(s->type == NST_FREE) - return; - - s->onPacketComplete = onPacketCompleteProc; - - s->onRecv = _onRORecv; // .. - s->onSend = _onSend; // Using the normal generic netbuf based send function. - - s->netparser_data = packetlentable; - - // Initial State -> Need Packet OPCode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - - - // Detach (if..) all buffers. - if(s->read.buf != NULL){ - _network_free_netbuf_async(s->read.buf); // - s->read.buf = NULL; - } - - if(s->write.buf != NULL){ - b = s->write.buf; - while(1){ - nb = b->next; - - _network_free_netbuf_async(b); - - b = nb; - } - - s->write.buf = NULL; - s->write.buf_last = NULL; - s->write.n_outstanding = 0; - } - - // not changing any limits on outstanding .. - // - + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ) +{ + register SESSION *s = &g_Session[fd]; + register netbuf b, nb; // used for potential free attached buffers. + + if (s->type == NST_FREE) + return; + + s->onPacketComplete = onPacketCompleteProc; + + s->onRecv = _onRORecv; // .. + s->onSend = _onSend; // Using the normal generic netbuf based send function. + + s->netparser_data = packetlentable; + + // Initial State -> Need Packet OPCode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + + + // Detach (if..) all buffers. + if (s->read.buf != NULL) { + _network_free_netbuf_async(s->read.buf); // + s->read.buf = NULL; + } + + if (s->write.buf != NULL) { + b = s->write.buf; + while (1) { + nb = b->next; + + _network_free_netbuf_async(b); + + b = nb; + } + + s->write.buf = NULL; + s->write.buf_last = NULL; + s->write.n_outstanding = 0; + } + + // not changing any limits on outstanding .. + // + }//end: network_parser_set_ro() diff --git a/src/common/network.h b/src/common/network.h index d7b463a2f..b883b41e6 100644 --- a/src/common/network.h +++ b/src/common/network.h @@ -3,7 +3,7 @@ #include #include "../common/cbasetypes.h" -#include "../common/netbuffer.h" +#include "../common/netbuffer.h" #include "../common/evdp.h" #ifndef MAXCONN @@ -11,79 +11,79 @@ #endif -typedef struct SESSION{ - EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) - - // Connection Type - enum{ NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; - - // Flags / Settings. - bool v6; // is v6? - bool disconnect_in_progress; // To prevent stack overflows / recursive calls. - - - union{ // union to save memory. - struct sockaddr_in v4; - struct sockaddr_in6 v6; - }addr; - - - // "lowlevel" Handlers - // (Implemented by the protocol specific parser) - // - bool (*onRecv)(int32 fd); // return false = disconnect - bool (*onSend)(int32 fd); // return false = disconnect - - // Event Handlers for LISTENER type sockets - // - // onConnect gets Called when a connection has been - // successfully accepted. - // Session entry is available in this Handler! - // A returncode of false will reejct the connection (disconnect) - // Note: When rejecting a connection in onConnect by returning false - // The onDisconnect handler wont get called! - // Note: the onConnect Handler is also responsible for setting - // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] - // - // onDisconnect gets called when a connection gets disconnected - // (by peer as well as by core) - // - bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) - void (*onDisconnect)(int32 fd); - - - // - // Parser specific data - // - void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) - void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); - - - // - // Buffers - // - struct{ - enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; - - uint32 head_left; - uint16 head[2]; - - netbuf buf; - } read; - - struct{ - uint32 max_outstanding; - uint32 n_outstanding; - - uint32 dataPos; - - netbuf buf, buf_last; - } write; - - // Application Level data Pointer - // (required for backward compatibility with previous athena socket system.) - void *data; - +typedef struct SESSION { + EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) + + // Connection Type + enum { NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; + + // Flags / Settings. + bool v6; // is v6? + bool disconnect_in_progress; // To prevent stack overflows / recursive calls. + + + union { // union to save memory. + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + + + // "lowlevel" Handlers + // (Implemented by the protocol specific parser) + // + bool (*onRecv)(int32 fd); // return false = disconnect + bool (*onSend)(int32 fd); // return false = disconnect + + // Event Handlers for LISTENER type sockets + // + // onConnect gets Called when a connection has been + // successfully accepted. + // Session entry is available in this Handler! + // A returncode of false will reejct the connection (disconnect) + // Note: When rejecting a connection in onConnect by returning false + // The onDisconnect handler wont get called! + // Note: the onConnect Handler is also responsible for setting + // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] + // + // onDisconnect gets called when a connection gets disconnected + // (by peer as well as by core) + // + bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) + void (*onDisconnect)(int32 fd); + + + // + // Parser specific data + // + void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) + void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); + + + // + // Buffers + // + struct { + enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; + + uint32 head_left; + uint16 head[2]; + + netbuf buf; + } read; + + struct { + uint32 max_outstanding; + uint32 n_outstanding; + + uint32 dataPos; + + netbuf buf, buf_last; + } write; + + // Application Level data Pointer + // (required for backward compatibility with previous athena socket system.) + void *data; + } SESSION; @@ -101,12 +101,12 @@ void network_final(); void network_do(); -/** +/** * Adds a new listner. * - * @param v6 v6 listner? - * @param *addr the address to listen on. - * @param port port to listen on + * @param v6 v6 listner? + * @param *addr the address to listen on. + * @param port port to listen on * * @return -1 on error otherwise the identifier of the new listener. */ @@ -116,26 +116,26 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port); /** * Tries to establish an outgoing connection. * - * @param v6 operate with IPv6 addresses? - * @param addr the address to connect to - * @param port the port to connect to - * @param from_addr the address to connect from (local source / optional if auto -> NULL) + * @param v6 operate with IPv6 addresses? + * @param addr the address to connect to + * @param port the port to connect to + * @param from_addr the address to connect from (local source / optional if auto -> NULL) * @param from_port the port to connect from (local source / optional if auto -> 0) - * @param onConnectionEstablishedHandler callback that gets called when the connection is established. - * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) + * @param onConnectionEstablishedHandler callback that gets called when the connection is established. + * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) * * @return -1 on error otherwise the identifier of the new connection */ int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) -); + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) + ); + - /** * Disconnects the given connection @@ -143,43 +143,43 @@ int32 network_connect(bool v6, * @param fd connection identifier. * * @Note: - * - onDisconnect callback gets called! - * - cleares (returns) all assigned buffers + * - onDisconnect callback gets called! + * - cleares (returns) all assigned buffers * */ void network_disconnect(int32 fd); -/** +/** * Attach's a netbuffer at the end of sending queue to the given connection * - * @param fd connection identifier - * @param buf netbuffer to attach. + * @param fd connection identifier + * @param buf netbuffer to attach. */ void network_send(int32 fd, netbuf buf); /** * Sets the parser to RO Protocol like Packet Parser. - * - * @param fd connection identifier - * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, - * @param onComplteProc callback for packet completion. + * + * @param fd connection identifier + * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, + * @param onComplteProc callback for packet completion. * * @note: - * PacketLen Table Fromat: - * each element's offsets represents th ro opcode. - * value is length. - * a length of 0 means the packet is dynamic. - * a length of UINT16_MAX means the packet is unknown. + * PacketLen Table Fromat: + * each element's offsets represents th ro opcode. + * value is length. + * a length of 0 means the packet is dynamic. + * a length of UINT16_MAX means the packet is unknown. * - * Static Packets must contain their hader in len so (0x64 == 55 ..) + * Static Packets must contain their hader in len so (0x64 == 55 ..) * */ void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ); + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ); #define ROPACKET_UNKNOWN UINT16_MAX #define ROPACKET_DYNLEN 0 diff --git a/src/common/nullpo.c b/src/common/nullpo.c index 4383109a7..ef2f3cd66 100644 --- a/src/common/nullpo.c +++ b/src/common/nullpo.c @@ -8,7 +8,7 @@ #include "../common/showmsg.h" // #include "logs.h" // 布石してみる -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap); /*====================================== @@ -17,75 +17,73 @@ static void nullpo_info_core(const char *file, int line, const char *func, int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) { - va_list ap; - - if (target != NULL) - return 0; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); - return 1; + va_list ap; + + if (target != NULL) + return 0; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); + return 1; } int nullpo_chk(const char *file, int line, const char *func, const void *target) { - if (target != NULL) - return 0; - - nullpo_info_core(file, line, func, NULL, NULL); - return 1; + if (target != NULL) + return 0; + + nullpo_info_core(file, line, func, NULL, NULL); + return 1; } /*====================================== * nullpo情報出力(外部呼出し向けラッパ) *--------------------------------------*/ -void nullpo_info_f(const char *file, int line, const char *func, - const char *fmt, ...) +void nullpo_info_f(const char *file, int line, const char *func, + const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); + va_list ap; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); } void nullpo_info(const char *file, int line, const char *func) { - nullpo_info_core(file, line, func, NULL, NULL); + nullpo_info_core(file, line, func, NULL, NULL); } /*====================================== * nullpo情報出力(Main) *--------------------------------------*/ -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap) { - if (file == NULL) - file = "??"; - - func = - func == NULL ? "unknown": - func[0] == '\0' ? "unknown": - func; - - ShowMessage("--- nullpo info --------------------------------------------\n"); - ShowMessage("%s:%d: in func `%s'\n", file, line, func); - if (fmt != NULL) - { - if (fmt[0] != '\0') - { - vprintf(fmt, ap); - - // 最後に改行したか確認 - if (fmt[strlen(fmt)-1] != '\n') - ShowMessage("\n"); - } - } - ShowMessage("--- end nullpo info ----------------------------------------\n"); - - // ここらでnullpoログをファイルに書き出せたら - // まとめて提出できるなと思っていたり。 + if (file == NULL) + file = "??"; + + func = + func == NULL ? "unknown": + func[0] == '\0' ? "unknown": + func; + + ShowMessage("--- nullpo info --------------------------------------------\n"); + ShowMessage("%s:%d: in func `%s'\n", file, line, func); + if (fmt != NULL) { + if (fmt[0] != '\0') { + vprintf(fmt, ap); + + // 最後に改行したか確認 + if (fmt[strlen(fmt)-1] != '\n') + ShowMessage("\n"); + } + } + ShowMessage("--- end nullpo info ----------------------------------------\n"); + + // ここらでnullpoログをファイルに書き出せたら + // まとめて提出できるなと思っていたり。 } diff --git a/src/common/nullpo.h b/src/common/nullpo.h index 8ee86a782..67679432f 100644 --- a/src/common/nullpo.h +++ b/src/common/nullpo.h @@ -71,45 +71,45 @@ #if defined(NULLPO_CHECK) #define nullpo_ret(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} #define nullpo_retv(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} #define nullpo_retr(ret, t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} #define nullpo_retb(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} // 可変引数マクロに関する条件コンパイル #if __STDC_VERSION__ >= 199901L /* C99に対応 */ #define nullpo_ret_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} #define nullpo_retv_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} #define nullpo_retr_f(ret, t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} #define nullpo_retb_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} #elif __GNUC__ >= 2 /* GCC用 */ #define nullpo_ret_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} #define nullpo_retv_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} #define nullpo_retr_f(ret, t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} #define nullpo_retb_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} #else @@ -189,7 +189,7 @@ int nullpo_chk(const char *file, int line, const char *func, const void *target) */ int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) - __attribute__((format(printf,5,6))); +__attribute__((format(printf,5,6))); /*====================================== @@ -217,9 +217,9 @@ void nullpo_info(const char *file, int line, const char *func); * 備考や関係変数の書き出しなどに *-------------------------------------- */ -void nullpo_info_f(const char *file, int line, const char *func, +void nullpo_info_f(const char *file, int line, const char *func, const char *fmt, ...) - __attribute__((format(printf,4,5))); +__attribute__((format(printf,4,5))); #endif /* _NULLPO_H_ */ diff --git a/src/common/raconf.c b/src/common/raconf.c index 2703560ff..e73154f50 100644 --- a/src/common/raconf.c +++ b/src/common/raconf.c @@ -1,7 +1,7 @@ -// +// // Athena style config parser -// (would be better to have "one" implementation instead of .. 4 :) -// +// (would be better to have "one" implementation instead of .. 4 :) +// // // Author: Florian Wilkemeyer // @@ -25,560 +25,571 @@ #define VARNAME_LEN 64 struct raconf { - DBMap *db; + DBMap *db; }; -struct conf_value{ - int64 intval; - bool bval; - double floatval; - size_t strval_len; // not includung \0 - char strval[16]; +struct conf_value { + int64 intval; + bool bval; + double floatval; + size_t strval_len; // not includung \0 + char strval[16]; }; -static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ - struct conf_value *v; - char *p; - size_t sz; - - sz = sizeof(struct conf_value); - if(val_len >= sizeof(v->strval)) - sz += (val_len - sizeof(v->strval) + 1); - - v = (struct conf_value*)aCalloc(1, sizeof(struct conf_value)); - if(v == NULL){ - ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); - return NULL; - } - - memcpy(v->strval, val, val_len); - v->strval[val_len+1] = '\0'; - v->strval_len = val_len; - - - // Parse boolean value: - if((val_len == 4) && (strncmpi("true", val, 4) == 0)) - v->bval = true; - else if((val_len == 3) && (strncmpi("yes", val, 3) == 0)) - v->bval = true; - else if((val_len == 3) && (strncmpi("oui", val, 3) == 0)) - v->bval = true; - else if((val_len == 2) && (strncmpi("si", val, 2) == 0)) - v->bval = true; - else if((val_len == 2) && (strncmpi("ja", val, 2) == 0)) - v->bval = true; - else if((val_len == 1) && (*val == '1')) - v->bval = true; - else if((val_len == 5) && (strncmpi("false", val, 5) == 0)) - v->bval = false; - else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if((val_len == 3) && (strncmpi("non", val, 3) == 0)) - v->bval = false; - else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if((val_len == 4) && (strncmpi("nein", val, 4) == 0)) - v->bval = false; - else if((val_len == 1) && (*val == '0')) - v->bval = false; - else - v->bval = false; // assume false. - - // Parse number - // Supported formats: - // prefix: 0x hex . - // postix: h for hex - // b for bin (dual) - if( (val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x')) ){//HEX! - if(val[val_len] == 'h'){ - val[val_len]= '\0'; - v->intval = strtoull(val, NULL, 16); - val[val_len] = 'h'; - }else - v->intval = strtoull(&val[2], NULL, 16); - }else if( val_len >= 1 && (val[val_len] == 'b') ){ //BIN - val[val_len] = '\0'; - v->intval = strtoull(val, NULL, 2); - val[val_len] = 'b'; - }else if( *val >='0' && *val <= '9'){ // begins with normal digit, so assume its dec. - // is it float? - bool is_float = false; - - for(p = val; *p != '\0'; p++){ - if(*p == '.'){ - v->floatval = strtod(val, NULL); - v->intval = (int64) v->floatval; - is_float = true; - break; - } - } - - if(is_float == false){ - v->intval = strtoull(val, NULL, 10); - v->floatval = (double) v->intval; - } - }else{ - // Everything else: lets use boolean for fallback - if(v->bval == true) - v->intval = 1; - else - v->intval = 0; - } - - return v; +static struct conf_value *makeValue(const char *key, char *val, size_t val_len) { + struct conf_value *v; + char *p; + size_t sz; + + sz = sizeof(struct conf_value); + if (val_len >= sizeof(v->strval)) + sz += (val_len - sizeof(v->strval) + 1); + + v = (struct conf_value *)aCalloc(1, sizeof(struct conf_value)); + if (v == NULL) { + ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); + return NULL; + } + + memcpy(v->strval, val, val_len); + v->strval[val_len+1] = '\0'; + v->strval_len = val_len; + + + // Parse boolean value: + if ((val_len == 4) && (strncmpi("true", val, 4) == 0)) + v->bval = true; + else if ((val_len == 3) && (strncmpi("yes", val, 3) == 0)) + v->bval = true; + else if ((val_len == 3) && (strncmpi("oui", val, 3) == 0)) + v->bval = true; + else if ((val_len == 2) && (strncmpi("si", val, 2) == 0)) + v->bval = true; + else if ((val_len == 2) && (strncmpi("ja", val, 2) == 0)) + v->bval = true; + else if ((val_len == 1) && (*val == '1')) + v->bval = true; + else if ((val_len == 5) && (strncmpi("false", val, 5) == 0)) + v->bval = false; + else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if ((val_len == 3) && (strncmpi("non", val, 3) == 0)) + v->bval = false; + else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if ((val_len == 4) && (strncmpi("nein", val, 4) == 0)) + v->bval = false; + else if ((val_len == 1) && (*val == '0')) + v->bval = false; + else + v->bval = false; // assume false. + + // Parse number + // Supported formats: + // prefix: 0x hex . + // postix: h for hex + // b for bin (dual) + if ((val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x'))) {//HEX! + if (val[val_len] == 'h') { + val[val_len]= '\0'; + v->intval = strtoull(val, NULL, 16); + val[val_len] = 'h'; + } else + v->intval = strtoull(&val[2], NULL, 16); + } else if (val_len >= 1 && (val[val_len] == 'b')) { //BIN + val[val_len] = '\0'; + v->intval = strtoull(val, NULL, 2); + val[val_len] = 'b'; + } else if (*val >='0' && *val <= '9') { // begins with normal digit, so assume its dec. + // is it float? + bool is_float = false; + + for (p = val; *p != '\0'; p++) { + if (*p == '.') { + v->floatval = strtod(val, NULL); + v->intval = (int64) v->floatval; + is_float = true; + break; + } + } + + if (is_float == false) { + v->intval = strtoull(val, NULL, 10); + v->floatval = (double) v->intval; + } + } else { + // Everything else: lets use boolean for fallback + if (v->bval == true) + v->intval = 1; + else + v->intval = 0; + } + + return v; }//end: makeValue() -static bool configParse(raconf inst, const char *fileName){ - FILE *fp; - char line[4096]; - char currentSection[SECTION_LEN]; - char *p; - char c; - int linecnt; - size_t linelen; - size_t currentSection_len; - - fp = fopen(fileName, "r"); - if(fp == NULL){ - ShowError("configParse: cannot open '%s' for reading.\n", fileName); - return false; - } - - - // Start with empty section: - currentSection[0] = '\0'; - currentSection_len = 0; - - // - linecnt = 0; - while(1){ - linecnt++; - - if(fgets(line, sizeof(line), fp) != line) - break; - - linelen = strlen(line); - p = line; - - // Skip whitespaces from beginning (space and tab) - _line_begin_skip_whities: - c = *p; - if(c == ' ' || c == '\t'){ - p++; - linelen--; - goto _line_begin_skip_whities; - } - - // Remove linebreaks as (cr or lf) and whitespaces from line end! - _line_end_skip_whities_and_breaks: - c = p[linelen-1]; - if(c == '\r' || c == '\n' || c == ' ' || c == '\t'){ - p[--linelen] = '\0'; - goto _line_end_skip_whities_and_breaks; - } - - // Empty line? - // or line starts with comment (commented out)? - if(linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') - continue; - - // Variable names can contain: - // A-Za-z-_.0-9 - // - // Sections start with [ .. ] (INI Style) - // - c = *p; - - // check what we have.. :) - if(c == '['){ // got section! - // Got Section! - // Search for ] - char *start = (p+1); - - while(1){ - ++p; - c = *p; - - if(c == '\0'){ - ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); - fclose(fp); - return false; - }else if(c == ']'){ // closing backet (section name termination) - if( (p - start + 1) > (sizeof(currentSection) ) ){ - ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); - fclose(fp); - return false; - } - - // Set section! - *p = '\0'; // add termination here. - memcpy(currentSection, start, (p-start)+1 ); // we'll copy \0, too! (we replaced the ] backet with \0.) - currentSection_len = (p-start); - - break; - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // skip .. (allowed char / specifier) - continue; - }else{ - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse section name - - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // Got variable! - // Search for '=' or ':' wich termiantes the name - char *start = p; - char *valuestart = NULL; - size_t start_len; - - while(1){ - ++p; - c = *p; - - if(c == '\0'){ - ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); - fclose(fp); - return false; - }else if( (c == '=') || (c == ':') ){ - // got name termination - - *p = '\0'; // Terminate it so (start) will hold the pointer to the name. - - break; - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // skip .. allowed char - continue; - }else{ - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse var name - - start_len = (p-start); - if(start_len >= VARNAME_LEN){ - ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); - fclose(fp); - return false; - }else if(start_len == 0){ - ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); - fclose(fp); - return false; - } - - - valuestart = (p+1); - - - // Skip whitespace from begin of value (tab and space) - _skip_value_begin_whities: - c = *valuestart; - if(c == ' ' || c == '\t'){ - valuestart++; - goto _skip_value_begin_whities; - } - - // Scan for value termination, - // wich can be \0 or comment start (// or ; (INI) ) - // - p = valuestart; - while(1){ - c = *p; - if(c == '\0'){ - // Terminated by line end. - break; - }else if(c == '/' && p[1] == '/'){ - // terminated by c++ style comment. - *p = '\0'; - break; - }else if(c == ';'){ - // terminated by ini style comment. - *p = '\0'; - break; - } - - p++; - }//endwhile: search var value end. - - - // Strip whitespaces from end of value. - if(valuestart != p){ // not empty! - p--; - _strip_value_end_whities: - c = *p; - if(c == ' ' || c == '\t'){ - *p = '\0'; - p--; - goto _strip_value_end_whities; - } - p++; - } - - - // Buildin Hook: - if( stricmp(start, "import") == 0){ - if( configParse(inst, valuestart) != true){ - ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); - } - }else{ - // put it to db. - struct conf_value *v, *o; - char key[ (SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. - size_t section_len; - - if(*currentSection == '\0'){ // empty / none - strncpy(key, "",9); - section_len = 9; - }else{ - strncpy(key, currentSection, currentSection_len); - section_len = currentSection_len; - } - - key[section_len] = '.'; // Delim - - strncpy(&key[section_len+1], start, start_len); - - key[section_len + start_len + 1] = '\0'; - - - v = makeValue(key, valuestart, (p-valuestart) ); - - // Try to get the old one before - o = strdb_get(inst->db, key); - if(o != NULL){ - strdb_remove(inst->db, key); - aFree(o); // - } - - strdb_put( inst->db, key, v); - } - - - }else{ - ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line) ); - fclose(fp); - return false; - } - - - - } - - - - fclose(fp); - return true; +static bool configParse(raconf inst, const char *fileName) +{ + FILE *fp; + char line[4096]; + char currentSection[SECTION_LEN]; + char *p; + char c; + int linecnt; + size_t linelen; + size_t currentSection_len; + + fp = fopen(fileName, "r"); + if (fp == NULL) { + ShowError("configParse: cannot open '%s' for reading.\n", fileName); + return false; + } + + + // Start with empty section: + currentSection[0] = '\0'; + currentSection_len = 0; + + // + linecnt = 0; + while (1) { + linecnt++; + + if (fgets(line, sizeof(line), fp) != line) + break; + + linelen = strlen(line); + p = line; + + // Skip whitespaces from beginning (space and tab) + _line_begin_skip_whities: + c = *p; + if (c == ' ' || c == '\t') { + p++; + linelen--; + goto _line_begin_skip_whities; + } + + // Remove linebreaks as (cr or lf) and whitespaces from line end! + _line_end_skip_whities_and_breaks: + c = p[linelen-1]; + if (c == '\r' || c == '\n' || c == ' ' || c == '\t') { + p[--linelen] = '\0'; + goto _line_end_skip_whities_and_breaks; + } + + // Empty line? + // or line starts with comment (commented out)? + if (linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') + continue; + + // Variable names can contain: + // A-Za-z-_.0-9 + // + // Sections start with [ .. ] (INI Style) + // + c = *p; + + // check what we have.. :) + if (c == '[') { // got section! + // Got Section! + // Search for ] + char *start = (p+1); + + while (1) { + ++p; + c = *p; + + if (c == '\0') { + ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); + fclose(fp); + return false; + } else if (c == ']') { // closing backet (section name termination) + if ((p - start + 1) > (sizeof(currentSection))) { + ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); + fclose(fp); + return false; + } + + // Set section! + *p = '\0'; // add termination here. + memcpy(currentSection, start, (p-start)+1); // we'll copy \0, too! (we replaced the ] backet with \0.) + currentSection_len = (p-start); + + break; + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // skip .. (allowed char / specifier) + continue; + } else { + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse section name + + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // Got variable! + // Search for '=' or ':' wich termiantes the name + char *start = p; + char *valuestart = NULL; + size_t start_len; + + while (1) { + ++p; + c = *p; + + if (c == '\0') { + ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); + fclose(fp); + return false; + } else if ((c == '=') || (c == ':')) { + // got name termination + + *p = '\0'; // Terminate it so (start) will hold the pointer to the name. + + break; + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // skip .. allowed char + continue; + } else { + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse var name + + start_len = (p-start); + if (start_len >= VARNAME_LEN) { + ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); + fclose(fp); + return false; + } else if (start_len == 0) { + ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); + fclose(fp); + return false; + } + + + valuestart = (p+1); + + + // Skip whitespace from begin of value (tab and space) + _skip_value_begin_whities: + c = *valuestart; + if (c == ' ' || c == '\t') { + valuestart++; + goto _skip_value_begin_whities; + } + + // Scan for value termination, + // wich can be \0 or comment start (// or ; (INI) ) + // + p = valuestart; + while (1) { + c = *p; + if (c == '\0') { + // Terminated by line end. + break; + } else if (c == '/' && p[1] == '/') { + // terminated by c++ style comment. + *p = '\0'; + break; + } else if (c == ';') { + // terminated by ini style comment. + *p = '\0'; + break; + } + + p++; + }//endwhile: search var value end. + + + // Strip whitespaces from end of value. + if (valuestart != p) { // not empty! + p--; + _strip_value_end_whities: + c = *p; + if (c == ' ' || c == '\t') { + *p = '\0'; + p--; + goto _strip_value_end_whities; + } + p++; + } + + + // Buildin Hook: + if (stricmp(start, "import") == 0) { + if (configParse(inst, valuestart) != true) { + ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); + } + } else { + // put it to db. + struct conf_value *v, *o; + char key[(SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. + size_t section_len; + + if (*currentSection == '\0') { // empty / none + strncpy(key, "",9); + section_len = 9; + } else { + strncpy(key, currentSection, currentSection_len); + section_len = currentSection_len; + } + + key[section_len] = '.'; // Delim + + strncpy(&key[section_len+1], start, start_len); + + key[section_len + start_len + 1] = '\0'; + + + v = makeValue(key, valuestart, (p-valuestart)); + + // Try to get the old one before + o = strdb_get(inst->db, key); + if (o != NULL) { + strdb_remove(inst->db, key); + aFree(o); // + } + + strdb_put(inst->db, key, v); + } + + + } else { + ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + + + } + + + + fclose(fp); + return true; }//end: configParse() #define MAKEKEY(dest, section, key) { size_t section_len, key_len; \ - if(section == NULL || *section == '\0'){ \ - strncpy(dest, "", 9); \ - section_len = 9; \ - }else{ \ - section_len = strlen(section); \ - strncpy(dest, section, section_len); \ - } \ - \ - dest[section_len] = '.'; \ - \ - key_len = strlen(key); \ - strncpy(&dest[section_len+1], key, key_len); \ - dest[section_len + key_len + 1] = '\0'; \ - } - - -raconf raconf_parse(const char *file_name){ - struct raconf *rc; - - rc = aCalloc(1, sizeof(struct raconf) ); - if(rc == NULL){ - ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); - return NULL; - } - - rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); - // - - if(configParse(rc, file_name) != true){ - ShowError("Failed to Parse Configuration file '%s'\n", file_name); - } - - return rc; + if(section == NULL || *section == '\0'){ \ + strncpy(dest, "", 9); \ + section_len = 9; \ + }else{ \ + section_len = strlen(section); \ + strncpy(dest, section, section_len); \ + } \ + \ + dest[section_len] = '.'; \ + \ + key_len = strlen(key); \ + strncpy(&dest[section_len+1], key, key_len); \ + dest[section_len + key_len + 1] = '\0'; \ + } + + +raconf raconf_parse(const char *file_name) +{ + struct raconf *rc; + + rc = aCalloc(1, sizeof(struct raconf)); + if (rc == NULL) { + ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); + return NULL; + } + + rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); + // + + if (configParse(rc, file_name) != true) { + ShowError("Failed to Parse Configuration file '%s'\n", file_name); + } + + return rc; }//end: raconf_parse() -void raconf_destroy(raconf rc){ - DBIterator *iter; - struct conf_value *v; - - // Clear all entrys in db. - iter = db_iterator(rc->db); - for( v = (struct conf_value*)dbi_first(iter); dbi_exists(iter); v = (struct conf_value*)dbi_next(iter) ){ - aFree(v); - } - dbi_destroy(iter); - - db_destroy(rc->db); - - aFree(rc); - +void raconf_destroy(raconf rc) +{ + DBIterator *iter; + struct conf_value *v; + + // Clear all entrys in db. + iter = db_iterator(rc->db); + for (v = (struct conf_value *)dbi_first(iter); dbi_exists(iter); v = (struct conf_value *)dbi_next(iter)) { + aFree(v); + } + dbi_destroy(iter); + + db_destroy(rc->db); + + aFree(rc); + }//end: raconf_destroy() -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->bval; +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->bval; }//end: raconf_getbool() -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return (float)v->floatval; + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return (float)v->floatval; }//end: raconf_getfloat() -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->intval; +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->intval; }//end: raconf_getint() -const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; +const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; - MAKEKEY(keystr, section, key); + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->strval; + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->strval; }//end: raconf_getstr() -bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->bval; - } - - }else{ - return v->bval; - } +bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->bval; + } + + } else { + return v->bval; + } }//end: raconf_getboolEx() -float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return (float)v->floatval; - } - - }else{ - return (float)v->floatval; - } - +float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return (float)v->floatval; + } + + } else { + return (float)v->floatval; + } + }//end: raconf_getfloatEx() -int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->intval; - } - - }else{ - return v->intval; - } +int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->intval; + } + + } else { + return v->intval; + } }//end: raconf_getintEx() -const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->strval; - } - - }else{ - return v->strval; - } +const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->strval; + } + + } else { + return v->strval; + } }//end: raconf_getstrEx() diff --git a/src/common/raconf.h b/src/common/raconf.h index 68a2b51b2..242c585bb 100644 --- a/src/common/raconf.h +++ b/src/common/raconf.h @@ -7,52 +7,52 @@ #include "../common/cbasetypes.h" // rAthena generic configuration file parser -// -// Config file Syntax is athena style -// extended with ini style support (including sections) // -// Comments are started with // or ; (ini style) +// Config file Syntax is athena style +// extended with ini style support (including sections) +// +// Comments are started with // or ; (ini style) // typedef struct raconf *raconf; -/** +/** * Parses a rAthna Configuration file - * + * * @param file_name path to the file to parse * * @returns not NULL incase of success */ -raconf raconf_parse(const char *file_name); +raconf raconf_parse(const char *file_name); -/** +/** * Frees a Handle received from raconf_parse * * @param rc - the handle to free */ -void raconf_destroy(raconf rc); +void raconf_destroy(raconf rc); -/** - * Gets the value for Section / Key pair, if key not exists returns _default! +/** + * Gets the value for Section / Key pair, if key not exists returns _default! * */ -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); -const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); +const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); /** - * Gets the value for Section / Key pair, but has fallback section option if not found in section, + * Gets the value for Section / Key pair, but has fallback section option if not found in section, * if not found in both - default gets returned. * */ bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default); float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default); int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default); -const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); +const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); diff --git a/src/common/random.c b/src/common/random.c index 5c048c7eb..ab9b0052f 100644 --- a/src/common/random.c +++ b/src/common/random.c @@ -5,10 +5,10 @@ #include "../common/timer.h" // gettick #include "random.h" #if defined(WIN32) - #include "../common/winapi.h" +#include "../common/winapi.h" #elif defined(HAVE_GETPID) || defined(HAVE_GETTID) - #include - #include +#include +#include #endif #include // time #include // init_genrand, genrand_int32, genrand_res53 @@ -17,34 +17,34 @@ /// Initializes the random number generator with an appropriate seed. void rnd_init(void) { - uint32 seed = gettick(); - seed += (uint32)time(NULL); + uint32 seed = gettick(); + seed += (uint32)time(NULL); #if defined(WIN32) - seed += GetCurrentProcessId(); - seed += GetCurrentThreadId(); + seed += GetCurrentProcessId(); + seed += GetCurrentThreadId(); #else #if defined(HAVE_GETPID) - seed += (uint32)getpid(); + seed += (uint32)getpid(); #endif // HAVE_GETPID #if defined(HAVE_GETTID) - seed += (uint32)gettid(); + seed += (uint32)gettid(); #endif // HAVE_GETTID #endif - init_genrand(seed); + init_genrand(seed); } /// Initializes the random number generator. void rnd_seed(uint32 seed) { - init_genrand(seed); + init_genrand(seed); } /// Generates a random number in the interval [0, SINT32_MAX] int32 rnd(void) { - return (int32)genrand_int31(); + return (int32)genrand_int31(); } @@ -52,7 +52,7 @@ int32 rnd(void) /// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0) uint32 rnd_roll(uint32 dice_faces) { - return (uint32)(rnd_uniform()*dice_faces); + return (uint32)(rnd_uniform()*dice_faces); } @@ -60,9 +60,9 @@ uint32 rnd_roll(uint32 dice_faces) /// Returns min if range is invalid. int32 rnd_value(int32 min, int32 max) { - if( min >= max ) - return min; - return min + (int32)(rnd_uniform()*(max-min+1)); + if (min >= max) + return min; + return min + (int32)(rnd_uniform()*(max-min+1)); } @@ -70,7 +70,7 @@ int32 rnd_value(int32 min, int32 max) /// NOTE: interval is open ended, so 1.0 is excluded double rnd_uniform(void) { - return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 + return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 } @@ -79,5 +79,5 @@ double rnd_uniform(void) /// NOTE: 53 bits is the maximum precision of a double double rnd_uniform53(void) { - return genrand_res53(); + return genrand_res53(); } diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 609ae3c50..cfa1587e5 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -15,33 +15,33 @@ #include "libconfig.h" #ifdef WIN32 - #include "../common/winapi.h" - - #ifdef DEBUGLOGMAP - #define DEBUGLOGPATH "log\\map-server.log" - #else - #ifdef DEBUGLOGCHAR - #define DEBUGLOGPATH "log\\char-server.log" - #else - #ifdef DEBUGLOGLOGIN - #define DEBUGLOGPATH "log\\login-server.log" - #endif - #endif - #endif +#include "../common/winapi.h" + +#ifdef DEBUGLOGMAP +#define DEBUGLOGPATH "log\\map-server.log" +#else +#ifdef DEBUGLOGCHAR +#define DEBUGLOGPATH "log\\char-server.log" +#else +#ifdef DEBUGLOGLOGIN +#define DEBUGLOGPATH "log\\login-server.log" +#endif +#endif +#endif #else - #include - - #ifdef DEBUGLOGMAP - #define DEBUGLOGPATH "log/map-server.log" - #else - #ifdef DEBUGLOGCHAR - #define DEBUGLOGPATH "log/char-server.log" - #else - #ifdef DEBUGLOGLOGIN - #define DEBUGLOGPATH "log/login-server.log" - #endif - #endif - #endif +#include + +#ifdef DEBUGLOGMAP +#define DEBUGLOGPATH "log/map-server.log" +#else +#ifdef DEBUGLOGCHAR +#define DEBUGLOGPATH "log/char-server.log" +#else +#ifdef DEBUGLOGLOGIN +#define DEBUGLOGPATH "log/login-server.log" +#endif +#endif +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -60,41 +60,41 @@ int console_msg_log = 0;//[Ind] msg error logging #define SBUF_SIZE 2054 // never put less that what's required for the debug message -#define NEWBUF(buf) \ - struct { \ - char s_[SBUF_SIZE]; \ - StringBuf *d_; \ - char *v_; \ - int l_; \ - } buf ={"",NULL,NULL,0}; \ -//define NEWBUF - -#define BUFVPRINTF(buf,fmt,args) \ - buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ - if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ - {/* static buffer */ \ - buf.v_ = buf.s_; \ - } \ - else \ - {/* dynamic buffer */ \ - buf.d_ = StringBuf_Malloc(); \ - buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ - buf.v_ = StringBuf_Value(buf.d_); \ - ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ - } \ -//define BUFVPRINTF +#define NEWBUF(buf) \ + struct { \ + char s_[SBUF_SIZE]; \ + StringBuf *d_; \ + char *v_; \ + int l_; \ + } buf ={"",NULL,NULL,0}; \ + //define NEWBUF + +#define BUFVPRINTF(buf,fmt,args) \ + buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ + if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ + {/* static buffer */ \ + buf.v_ = buf.s_; \ + } \ + else \ + {/* dynamic buffer */ \ + buf.d_ = StringBuf_Malloc(); \ + buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ + buf.v_ = StringBuf_Value(buf.d_); \ + ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ + } \ + //define BUFVPRINTF #define BUFVAL(buf) buf.v_ #define BUFLEN(buf) buf.l_ -#define FREEBUF(buf) \ - if( buf.d_ ) \ - { \ - StringBuf_Free(buf.d_); \ - buf.d_ = NULL; \ - } \ - buf.v_ = NULL; \ -//define FREEBUF +#define FREEBUF(buf) \ + if( buf.d_ ) \ + { \ + StringBuf_Free(buf.d_); \ + buf.d_ = NULL; \ + } \ + buf.v_ = NULL; \ + //define FREEBUF /////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 @@ -104,38 +104,38 @@ int console_msg_log = 0;//[Ind] msg error logging // ansi compatible printf with control sequence parser for windows // fast hack, handle with care, not everything implemented // -// \033[#;...;#m - Set Graphics Rendition (SGR) +// \033[#;...;#m - Set Graphics Rendition (SGR) // -// printf("\x1b[1;31;40m"); // Bright red on black -// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) -// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white +// printf("\x1b[1;31;40m"); // Bright red on black +// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) +// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white // // Style Foreground Background -// 1st Digit 2nd Digit 3rd Digit RGB -// 0 - Reset 30 - Black 40 - Black 000 -// 1 - FG Bright 31 - Red 41 - Red 100 -// 2 - Unknown 32 - Green 42 - Green 010 -// 3 - Blink 33 - Yellow 43 - Yellow 110 -// 4 - Underline 34 - Blue 44 - Blue 001 -// 5 - BG Bright 35 - Magenta 45 - Magenta 101 -// 6 - Unknown 36 - Cyan 46 - Cyan 011 -// 7 - Reverse 37 - White 47 - White 111 +// 1st Digit 2nd Digit 3rd Digit RGB +// 0 - Reset 30 - Black 40 - Black 000 +// 1 - FG Bright 31 - Red 41 - Red 100 +// 2 - Unknown 32 - Green 42 - Green 010 +// 3 - Blink 33 - Yellow 43 - Yellow 110 +// 4 - Underline 34 - Blue 44 - Blue 001 +// 5 - BG Bright 35 - Magenta 45 - Magenta 101 +// 6 - Unknown 36 - Cyan 46 - Cyan 011 +// 7 - Reverse 37 - White 47 - White 111 // 8 - Concealed (invisible) // // \033[#A - Cursor Up (CUU) -// Moves the cursor up by the specified number of lines without changing columns. +// Moves the cursor up by the specified number of lines without changing columns. // If the cursor is already on the top line, this sequence is ignored. \e[A is equivalent to \e[1A. // // \033[#B - Cursor Down (CUD) -// Moves the cursor down by the specified number of lines without changing columns. +// Moves the cursor down by the specified number of lines without changing columns. // If the cursor is already on the bottom line, this sequence is ignored. \e[B is equivalent to \e[1B. // // \033[#C - Cursor Forward (CUF) -// Moves the cursor forward by the specified number of columns without changing lines. +// Moves the cursor forward by the specified number of columns without changing lines. // If the cursor is already in the rightmost column, this sequence is ignored. \e[C is equivalent to \e[1C. // // \033[#D - Cursor Backward (CUB) -// Moves the cursor back by the specified number of columns without changing lines. +// Moves the cursor back by the specified number of columns without changing lines. // If the cursor is already in the leftmost column, this sequence is ignored. \e[D is equivalent to \e[1D. // // \033[#E - Cursor Next Line (CNL) @@ -148,15 +148,15 @@ int console_msg_log = 0;//[Ind] msg error logging // Moves the cursor to indicated column in current row. \e[G is equivalent to \e[1G. // // \033[#;#H - Cursor Position (CUP) -// Moves the cursor to the specified position. The first # specifies the line number, -// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: +// Moves the cursor to the specified position. The first # specifies the line number, +// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: // the upper-left corner of the screen (line 1, column 1). // // \033[#;#f - Horizontal & Vertical Position // (same as \033[#;#H) // // \033[s - Save Cursor Position (SCP) -// The current cursor position is saved. +// The current cursor position is saved. // // \033[u - Restore cursor position (RCP) // Restores the cursor position saved with the (SCP) sequence \033[s. @@ -194,331 +194,295 @@ Escape sequences for Select Character Set #define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle)) /////////////////////////////////////////////////////////////////////////////// -int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) +int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) { - ///////////////////////////////////////////////////////////////// - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - static COORD saveposition = {0,0}; - */ - - ///////////////////////////////////////////////////////////////// - DWORD written; - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if(!fmt || !*fmt) - return 0; - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - if( !is_console(handle) && stdout_with_ansisequence ) - { - WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); - return 0; - } - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) - { // find the escape character - if( 0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0) ) // write up to the escape - WriteFile(handle, p, (DWORD)(q-p), &written, 0); - - if( q[1]!='[' ) - { // write the escape char (whatever purpose it has) - if(0==WriteConsole(handle, q, 1, &written, 0) ) - WriteFile(handle,q, 1, &written, 0); - p=q+1; //and start searching again - } - else - { // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - uint8 numbers[16], numpoint=0; - CONSOLE_SCREEN_BUFFER_INFO info; - - // initialize - GetConsoleScreenBufferInfo(handle, &info); - memset(numbers,0,sizeof(numbers)); - - // skip escape and bracket - q=q+2; - for(;;) - { - if( ISDIGIT(*q) ) - { // add number to number array, only accept 2digits, shift out the rest - // so // \033[123456789m will become \033[89m - numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); - ++q; - // and next character - continue; - } - else if( *q == ';' ) - { // delimiter - if(numpoint7) num=7; // set white for 37, 38 and 39 - info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); - if( (num & 0x01)>0 ) // lowest bit set = red - info.wAttributes |= FOREGROUND_RED; - if( (num & 0x02)>0 ) // second bit set = green - info.wAttributes |= FOREGROUND_GREEN; - if( (num & 0x04)>0 ) // third bit set = blue - info.wAttributes |= FOREGROUND_BLUE; - } - else if( 0x40 == (0xF0 & numbers[i]) ) - { // background - uint8 num = numbers[i]&0x0F; - if(num==9) info.wAttributes |= BACKGROUND_INTENSITY; - if(num>7) num=7; // set white for 47, 48 and 49 - info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); - if( (num & 0x01)>0 ) // lowest bit set = red - info.wAttributes |= BACKGROUND_RED; - if( (num & 0x02)>0 ) // second bit set = green - info.wAttributes |= BACKGROUND_GREEN; - if( (num & 0x04)>0 ) // third bit set = blue - info.wAttributes |= BACKGROUND_BLUE; - } - } - // set the attributes - SetConsoleTextAttribute(handle, info.wAttributes); - } - else if( *q=='J' ) - { // \033[#J - Erase Display (ED) - // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. - // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. - // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - int cnt; - DWORD tmp; - COORD origin = {0,0}; - if(num==1) - { // chars from start up to and including cursor - cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; - } - else if(num==2) - { // Number of chars on screen. - cnt = info.dwSize.X * info.dwSize.Y; - SetConsoleCursorPosition(handle, origin); - } - else// 0 and default - { // number of chars from cursor to end - origin = info.dwCursorPosition; - cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } - else if( *q=='K' ) - { // \033[K : clear line from actual position to end of the line - // \033[0K - Clears all characters from the cursor position to the end of the line. - // \033[1K - Clears all characters from start of line to the cursor position. - // \033[2K - Clears all characters of the whole line. - - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 - SHORT cnt; - DWORD tmp; - if(num==1) - { - cnt = info.dwCursorPosition.X + 1; - } - else if(num==2) - { - cnt = info.dwSize.X; - } - else// 0 and default - { - origin = info.dwCursorPosition; - cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } - else if( *q == 'H' || *q == 'f' ) - { // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - // The first # specifies the line number, the second # specifies the column. - // The default for both is 1 - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; - - if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.Y = info.dwSize.X-1; - if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q=='s' ) - { // \033[s - Save Cursor Position (SCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(handle, &info); - saveposition = info.dwCursorPosition; - */ - } - else if( *q=='u' ) - { // \033[u - Restore cursor position (RCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - SetConsoleCursorPosition(handle, saveposition); - */ - } - else if( *q == 'A' ) - { // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.Y < 0 ) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'B' ) - { // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.Y >= info.dwSize.Y ) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'C' ) - { // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.X >= info.dwSize.X ) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'D' ) - { // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.X < 0 ) - info.dwCursorPosition.X = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'E' ) - { // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if( info.dwCursorPosition.Y >= info.dwSize.Y ) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'F' ) - { // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if( info.dwCursorPosition.Y < 0 ) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'G' ) - { // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - - if( info.dwCursorPosition.X >= info.dwSize.X ) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') - { // not implemented, just skip - } - else - { // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - if( 0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0) ) - WriteFile(handle, p, (DWORD)strlen(p), &written, 0); - FREEBUF(tempbuf); - return 0; + ///////////////////////////////////////////////////////////////// + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + static COORD saveposition = {0,0}; + */ + + ///////////////////////////////////////////////////////////////// + DWORD written; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if (!fmt || !*fmt) + return 0; + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + if (!is_console(handle) && stdout_with_ansisequence) { + WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); + return 0; + } + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) { + // find the escape character + if (0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0)) // write up to the escape + WriteFile(handle, p, (DWORD)(q-p), &written, 0); + + if (q[1]!='[') { + // write the escape char (whatever purpose it has) + if (0==WriteConsole(handle, q, 1, &written, 0)) + WriteFile(handle,q, 1, &written, 0); + p=q+1; //and start searching again + } else { + // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + uint8 numbers[16], numpoint=0; + CONSOLE_SCREEN_BUFFER_INFO info; + + // initialize + GetConsoleScreenBufferInfo(handle, &info); + memset(numbers,0,sizeof(numbers)); + + // skip escape and bracket + q=q+2; + for (;;) { + if (ISDIGIT(*q)) { + // add number to number array, only accept 2digits, shift out the rest + // so // \033[123456789m will become \033[89m + numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); + ++q; + // and next character + continue; + } else if (*q == ';') { + // delimiter + if (numpoint7) num=7; // set white for 37, 38 and 39 + info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); + if ((num & 0x01)>0) // lowest bit set = red + info.wAttributes |= FOREGROUND_RED; + if ((num & 0x02)>0) // second bit set = green + info.wAttributes |= FOREGROUND_GREEN; + if ((num & 0x04)>0) // third bit set = blue + info.wAttributes |= FOREGROUND_BLUE; + } else if (0x40 == (0xF0 & numbers[i])) { + // background + uint8 num = numbers[i]&0x0F; + if (num==9) info.wAttributes |= BACKGROUND_INTENSITY; + if (num>7) num=7; // set white for 47, 48 and 49 + info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); + if ((num & 0x01)>0) // lowest bit set = red + info.wAttributes |= BACKGROUND_RED; + if ((num & 0x02)>0) // second bit set = green + info.wAttributes |= BACKGROUND_GREEN; + if ((num & 0x04)>0) // third bit set = blue + info.wAttributes |= BACKGROUND_BLUE; + } + } + // set the attributes + SetConsoleTextAttribute(handle, info.wAttributes); + } else if (*q=='J') { + // \033[#J - Erase Display (ED) + // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. + // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. + // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + int cnt; + DWORD tmp; + COORD origin = {0,0}; + if (num==1) { + // chars from start up to and including cursor + cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; + } else if (num==2) { + // Number of chars on screen. + cnt = info.dwSize.X * info.dwSize.Y; + SetConsoleCursorPosition(handle, origin); + } else { // 0 and default + // number of chars from cursor to end + origin = info.dwCursorPosition; + cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } else if (*q=='K') { + // \033[K : clear line from actual position to end of the line + // \033[0K - Clears all characters from the cursor position to the end of the line. + // \033[1K - Clears all characters from start of line to the cursor position. + // \033[2K - Clears all characters of the whole line. + + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 + SHORT cnt; + DWORD tmp; + if (num==1) { + cnt = info.dwCursorPosition.X + 1; + } else if (num==2) { + cnt = info.dwSize.X; + } else { // 0 and default + origin = info.dwCursorPosition; + cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } else if (*q == 'H' || *q == 'f') { + // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + // The first # specifies the line number, the second # specifies the column. + // The default for both is 1 + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; + + if (info.dwCursorPosition.X >= info.dwSize.X) info.dwCursorPosition.Y = info.dwSize.X-1; + if (info.dwCursorPosition.Y >= info.dwSize.Y) info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q=='s') { + // \033[s - Save Cursor Position (SCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(handle, &info); + saveposition = info.dwCursorPosition; + */ + } else if (*q=='u') { + // \033[u - Restore cursor position (RCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + SetConsoleCursorPosition(handle, saveposition); + */ + } else if (*q == 'A') { + // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.Y < 0) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'B') { + // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.Y >= info.dwSize.Y) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'C') { + // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.X >= info.dwSize.X) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'D') { + // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.X < 0) + info.dwCursorPosition.X = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'E') { + // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if (info.dwCursorPosition.Y >= info.dwSize.Y) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'F') { + // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if (info.dwCursorPosition.Y < 0) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'G') { + // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + + if (info.dwCursorPosition.X >= info.dwSize.X) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { + // not implemented, just skip + } else { + // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + if (0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0)) + WriteFile(handle, p, (DWORD)strlen(p), &written, 0); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(HANDLE handle, const char *fmt, ...) +int FPRINTF(HANDLE handle, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(handle,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(handle,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH(handle) @@ -532,129 +496,109 @@ int FPRINTF(HANDLE handle, const char *fmt, ...) #define is_console(file) (0!=isatty(fileno(file))) //vprintf_without_ansiformats -int VFPRINTF(FILE *file, const char *fmt, va_list argptr) +int VFPRINTF(FILE *file, const char *fmt, va_list argptr) { - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if(!fmt || !*fmt) - return 0; - - if( is_console(file) || stdout_with_ansisequence ) - { - vfprintf(file, fmt, argptr); - return 0; - } - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) - { // find the escape character - fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape - if( q[1]!='[' ) - { // write the escape char (whatever purpose it has) - fprintf(file, "%.*s", 1, q); - p=q+1; //and start searching again - } - else - { // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - - // skip escape and bracket - q=q+2; - while(1) - { - if( ISDIGIT(*q) ) - { - ++q; - // and next character - continue; - } - else if( *q == ';' ) - { // delimiter - ++q; - // and next number - continue; - } - else if( *q == 'm' ) - { // \033[#;...;#m - Set Graphics Rendition (SGR) - // set the attributes - } - else if( *q=='J' ) - { // \033[#J - Erase Display (ED) - } - else if( *q=='K' ) - { // \033[K : clear line from actual position to end of the line - } - else if( *q == 'H' || *q == 'f' ) - { // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - } - else if( *q=='s' ) - { // \033[s - Save Cursor Position (SCP) - } - else if( *q=='u' ) - { // \033[u - Restore cursor position (RCP) - } - else if( *q == 'A' ) - { // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - } - else if( *q == 'B' ) - { // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - } - else if( *q == 'C' ) - { // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - } - else if( *q == 'D' ) - { // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - } - else if( *q == 'E' ) - { // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - } - else if( *q == 'F' ) - { // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - } - else if( *q == 'G' ) - { // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - } - else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') - { // not implemented, just skip - } - else - { // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - fprintf(file, "%s", p); - FREEBUF(tempbuf); - return 0; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if (!fmt || !*fmt) + return 0; + + if (is_console(file) || stdout_with_ansisequence) { + vfprintf(file, fmt, argptr); + return 0; + } + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) { + // find the escape character + fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape + if (q[1]!='[') { + // write the escape char (whatever purpose it has) + fprintf(file, "%.*s", 1, q); + p=q+1; //and start searching again + } else { + // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + + // skip escape and bracket + q=q+2; + while (1) { + if (ISDIGIT(*q)) { + ++q; + // and next character + continue; + } else if (*q == ';') { + // delimiter + ++q; + // and next number + continue; + } else if (*q == 'm') { + // \033[#;...;#m - Set Graphics Rendition (SGR) + // set the attributes + } else if (*q=='J') { + // \033[#J - Erase Display (ED) + } else if (*q=='K') { + // \033[K : clear line from actual position to end of the line + } else if (*q == 'H' || *q == 'f') { + // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + } else if (*q=='s') { + // \033[s - Save Cursor Position (SCP) + } else if (*q=='u') { + // \033[u - Restore cursor position (RCP) + } else if (*q == 'A') { + // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + } else if (*q == 'B') { + // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + } else if (*q == 'C') { + // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + } else if (*q == 'D') { + // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + } else if (*q == 'E') { + // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + } else if (*q == 'F') { + // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + } else if (*q == 'G') { + // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { + // not implemented, just skip + } else { + // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + fprintf(file, "%s", p); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(FILE *file, const char *fmt, ...) +int FPRINTF(FILE *file, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(file,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(file,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH fflush @@ -677,216 +621,225 @@ char timestamp_format[20] = ""; //For displaying Timestamps int _vShowMessage(enum msg_type flag, const char *string, va_list ap) { - va_list apcopy; - char prefix[100]; + va_list apcopy; + char prefix[100]; #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - FILE *fp; + FILE *fp; #endif - - if (!string || *string == '\0') { - ShowError("Empty string passed to _vShowMessage().\n"); - return 1; - } - /** - * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. - **/ + + if (!string || *string == '\0') { + ShowError("Empty string passed to _vShowMessage().\n"); + return 1; + } + /** + * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. + **/ #if defined(BUILDBOT) - if( flag == MSG_WARNING || - flag == MSG_ERROR || - flag == MSG_SQL ) { - buildbotflag = 1; - } + if (flag == MSG_WARNING || + flag == MSG_ERROR || + flag == MSG_SQL) { + buildbotflag = 1; + } #endif - if( - ( flag == MSG_WARNING && console_msg_log&1 ) || - ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || - ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] - FILE *log = NULL; - if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { - char timestring[255]; - time_t curtime; - time(&curtime); - strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - fprintf(log,"(%s) [ %s ] : ", - timestring, - flag == MSG_WARNING ? "Warning" : - flag == MSG_ERROR ? "Error" : - flag == MSG_SQL ? "SQL Error" : - flag == MSG_DEBUG ? "Debug" : - "Unknown"); - va_copy(apcopy, ap); - vfprintf(log,string,apcopy); - va_end(apcopy); - fclose(log); - } - } - if( - (flag == MSG_INFORMATION && msg_silent&1) || - (flag == MSG_STATUS && msg_silent&2) || - (flag == MSG_NOTICE && msg_silent&4) || - (flag == MSG_WARNING && msg_silent&8) || - (flag == MSG_ERROR && msg_silent&16) || - (flag == MSG_SQL && msg_silent&16) || - (flag == MSG_DEBUG && msg_silent&32) - ) - return 0; //Do not print it. - - if (timestamp_format[0] && flag != MSG_NONE) - { //Display time format. [Skotlex] - time_t t = time(NULL); - strftime(prefix, 80, timestamp_format, localtime(&t)); - } else prefix[0]='\0'; - - switch (flag) { - case MSG_NONE: // direct printf replacement - break; - case MSG_STATUS: //Bright Green (To inform about good things) - strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); - break; - case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] - strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); - break; - case MSG_INFORMATION: //Bright White (Variable information) - strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); - break; - case MSG_NOTICE: //Bright White (Less than a warning) - strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); - break; - case MSG_WARNING: //Bright Yellow - strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); - break; - case MSG_DEBUG: //Bright Cyan, important stuff! - strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); - break; - case MSG_ERROR: //Bright Red (Regular errors) - strcat(prefix,CL_RED"[Error]"CL_RESET":"); - break; - case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) - strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); - break; - default: - ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); - return 1; - } - - if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) - { //Send Errors to StdErr [Skotlex] - FPRINTF(STDERR, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDERR, string, apcopy); - va_end(apcopy); - FFLUSH(STDERR); - } else { - if (flag != MSG_NONE) - FPRINTF(STDOUT, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDOUT, string, apcopy); - va_end(apcopy); - FFLUSH(STDOUT); - } + if ( + (flag == MSG_WARNING && console_msg_log&1) || + ((flag == MSG_ERROR || flag == MSG_SQL) && console_msg_log&2) || + (flag == MSG_DEBUG && console_msg_log&4)) { //[Ind] + FILE *log = NULL; + if ((log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+"))) { + char timestring[255]; + time_t curtime; + time(&curtime); + strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + fprintf(log,"(%s) [ %s ] : ", + timestring, + flag == MSG_WARNING ? "Warning" : + flag == MSG_ERROR ? "Error" : + flag == MSG_SQL ? "SQL Error" : + flag == MSG_DEBUG ? "Debug" : + "Unknown"); + va_copy(apcopy, ap); + vfprintf(log,string,apcopy); + va_end(apcopy); + fclose(log); + } + } + if ( + (flag == MSG_INFORMATION && msg_silent&1) || + (flag == MSG_STATUS && msg_silent&2) || + (flag == MSG_NOTICE && msg_silent&4) || + (flag == MSG_WARNING && msg_silent&8) || + (flag == MSG_ERROR && msg_silent&16) || + (flag == MSG_SQL && msg_silent&16) || + (flag == MSG_DEBUG && msg_silent&32) + ) + return 0; //Do not print it. + + if (timestamp_format[0] && flag != MSG_NONE) { + //Display time format. [Skotlex] + time_t t = time(NULL); + strftime(prefix, 80, timestamp_format, localtime(&t)); + } else prefix[0]='\0'; + + switch (flag) { + case MSG_NONE: // direct printf replacement + break; + case MSG_STATUS: //Bright Green (To inform about good things) + strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); + break; + case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] + strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); + break; + case MSG_INFORMATION: //Bright White (Variable information) + strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); + break; + case MSG_NOTICE: //Bright White (Less than a warning) + strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); + break; + case MSG_WARNING: //Bright Yellow + strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); + break; + case MSG_DEBUG: //Bright Cyan, important stuff! + strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); + break; + case MSG_ERROR: //Bright Red (Regular errors) + strcat(prefix,CL_RED"[Error]"CL_RESET":"); + break; + case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) + strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); + break; + default: + ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); + return 1; + } + + if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) { + //Send Errors to StdErr [Skotlex] + FPRINTF(STDERR, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDERR, string, apcopy); + va_end(apcopy); + FFLUSH(STDERR); + } else { + if (flag != MSG_NONE) + FPRINTF(STDOUT, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDOUT, string, apcopy); + va_end(apcopy); + FFLUSH(STDOUT); + } #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - if(strlen(DEBUGLOGPATH) > 0) { - fp=fopen(DEBUGLOGPATH,"a"); - if (fp == NULL) { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); - FFLUSH(STDERR); - } else { - fprintf(fp,"%s ", prefix); - va_copy(apcopy, ap); - vfprintf(fp,string,apcopy); - va_end(apcopy); - fclose(fp); - } - } else { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); - FFLUSH(STDERR); - } + if (strlen(DEBUGLOGPATH) > 0) { + fp=fopen(DEBUGLOGPATH,"a"); + if (fp == NULL) { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); + FFLUSH(STDERR); + } else { + fprintf(fp,"%s ", prefix); + va_copy(apcopy, ap); + vfprintf(fp,string,apcopy); + va_end(apcopy); + fclose(fp); + } + } else { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); + FFLUSH(STDERR); + } #endif - return 0; + return 0; } void ClearScreen(void) { #ifndef _WIN32 - ShowMessage(CL_CLS); // to prevent empty string passed messages + ShowMessage(CL_CLS); // to prevent empty string passed messages #endif } int _ShowMessage(enum msg_type flag, const char *string, ...) { - int ret; - va_list ap; - va_start(ap, string); - ret = _vShowMessage(flag, string, ap); - va_end(ap); - return ret; + int ret; + va_list ap; + va_start(ap, string); + ret = _vShowMessage(flag, string, ap); + va_end(ap); + return ret; } // direct printf replacement -void ShowMessage(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NONE, string, ap); - va_end(ap); +void ShowMessage(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NONE, string, ap); + va_end(ap); } -void ShowStatus(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_STATUS, string, ap); - va_end(ap); +void ShowStatus(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_STATUS, string, ap); + va_end(ap); } -void ShowSQL(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_SQL, string, ap); - va_end(ap); +void ShowSQL(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_SQL, string, ap); + va_end(ap); } -void ShowInfo(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_INFORMATION, string, ap); - va_end(ap); +void ShowInfo(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_INFORMATION, string, ap); + va_end(ap); } -void ShowNotice(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NOTICE, string, ap); - va_end(ap); +void ShowNotice(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NOTICE, string, ap); + va_end(ap); } -void ShowWarning(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_WARNING, string, ap); - va_end(ap); +void ShowWarning(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_WARNING, string, ap); + va_end(ap); } void ShowConfigWarning(config_setting_t *config, const char *string, ...) { - StringBuf buf; - va_list ap; - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, string); - StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); - va_start(ap, string); - _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); - va_end(ap); - StringBuf_Destroy(&buf); + StringBuf buf; + va_list ap; + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, string); + StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); + va_start(ap, string); + _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); + va_end(ap); + StringBuf_Destroy(&buf); } -void ShowDebug(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_DEBUG, string, ap); - va_end(ap); +void ShowDebug(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_DEBUG, string, ap); + va_end(ap); } -void ShowError(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_ERROR, string, ap); - va_end(ap); +void ShowError(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_ERROR, string, ap); + va_end(ap); } -void ShowFatalError(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_FATALERROR, string, ap); - va_end(ap); +void ShowFatalError(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_FATALERROR, string, ap); + va_end(ap); } diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 0d6cb5c9f..8c2b5bd42 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -14,58 +14,58 @@ // \033[0m : reset color parameter // \033[1m : use bold for font -#define CL_RESET "\033[0m" -#define CL_CLS "\033[2J" -#define CL_CLL "\033[K" +#define CL_RESET "\033[0m" +#define CL_CLS "\033[2J" +#define CL_CLL "\033[K" // font settings -#define CL_BOLD "\033[1m" -#define CL_NORM CL_RESET -#define CL_NORMAL CL_RESET -#define CL_NONE CL_RESET +#define CL_BOLD "\033[1m" +#define CL_NORM CL_RESET +#define CL_NORMAL CL_RESET +#define CL_NONE CL_RESET // foreground color and bold font (bright color on windows) -#define CL_WHITE "\033[1;37m" -#define CL_GRAY "\033[1;30m" -#define CL_RED "\033[1;31m" -#define CL_GREEN "\033[1;32m" -#define CL_YELLOW "\033[1;33m" -#define CL_BLUE "\033[1;34m" -#define CL_MAGENTA "\033[1;35m" -#define CL_CYAN "\033[1;36m" +#define CL_WHITE "\033[1;37m" +#define CL_GRAY "\033[1;30m" +#define CL_RED "\033[1;31m" +#define CL_GREEN "\033[1;32m" +#define CL_YELLOW "\033[1;33m" +#define CL_BLUE "\033[1;34m" +#define CL_MAGENTA "\033[1;35m" +#define CL_CYAN "\033[1;36m" // background color -#define CL_BG_BLACK "\033[40m" -#define CL_BG_RED "\033[41m" -#define CL_BG_GREEN "\033[42m" -#define CL_BG_YELLOW "\033[43m" -#define CL_BG_BLUE "\033[44m" -#define CL_BG_MAGENTA "\033[45m" -#define CL_BG_CYAN "\033[46m" -#define CL_BG_WHITE "\033[47m" +#define CL_BG_BLACK "\033[40m" +#define CL_BG_RED "\033[41m" +#define CL_BG_GREEN "\033[42m" +#define CL_BG_YELLOW "\033[43m" +#define CL_BG_BLUE "\033[44m" +#define CL_BG_MAGENTA "\033[45m" +#define CL_BG_CYAN "\033[46m" +#define CL_BG_WHITE "\033[47m" // foreground color and normal font (normal color on windows) -#define CL_LT_BLACK "\033[0;30m" -#define CL_LT_RED "\033[0;31m" -#define CL_LT_GREEN "\033[0;32m" -#define CL_LT_YELLOW "\033[0;33m" -#define CL_LT_BLUE "\033[0;34m" -#define CL_LT_MAGENTA "\033[0;35m" -#define CL_LT_CYAN "\033[0;36m" -#define CL_LT_WHITE "\033[0;37m" +#define CL_LT_BLACK "\033[0;30m" +#define CL_LT_RED "\033[0;31m" +#define CL_LT_GREEN "\033[0;32m" +#define CL_LT_YELLOW "\033[0;33m" +#define CL_LT_BLUE "\033[0;34m" +#define CL_LT_MAGENTA "\033[0;35m" +#define CL_LT_CYAN "\033[0;36m" +#define CL_LT_WHITE "\033[0;37m" // foreground color and bold font (bright color on windows) -#define CL_BT_BLACK "\033[1;30m" -#define CL_BT_RED "\033[1;31m" -#define CL_BT_GREEN "\033[1;32m" -#define CL_BT_YELLOW "\033[1;33m" -#define CL_BT_BLUE "\033[1;34m" -#define CL_BT_MAGENTA "\033[1;35m" -#define CL_BT_CYAN "\033[1;36m" -#define CL_BT_WHITE "\033[1;37m" +#define CL_BT_BLACK "\033[1;30m" +#define CL_BT_RED "\033[1;31m" +#define CL_BT_GREEN "\033[1;32m" +#define CL_BT_YELLOW "\033[1;33m" +#define CL_BT_BLUE "\033[1;34m" +#define CL_BT_MAGENTA "\033[1;35m" +#define CL_BT_CYAN "\033[1;36m" +#define CL_BT_WHITE "\033[1;37m" -#define CL_WTBL "\033[37;44m" // white on blue -#define CL_XXBL "\033[0;44m" // default on blue -#define CL_PASS "\033[0;32;42m" // green on green +#define CL_WTBL "\033[37;44m" // white on blue +#define CL_XXBL "\033[0;44m" // default on blue +#define CL_PASS "\033[0;32;42m" // green on green -#define CL_SPACE " " // space aquivalent of the print messages +#define CL_SPACE " " // space aquivalent of the print messages extern int stdout_with_ansisequence; //If the color ansi sequences are to be used. [flaviojs] extern int msg_silent; //Specifies how silent the console is. [Skotlex] @@ -73,15 +73,15 @@ extern int console_msg_log; //Specifies what error messages to log. [Ind] extern char timestamp_format[20]; //For displaying Timestamps [Skotlex] enum msg_type { - MSG_NONE, - MSG_STATUS, - MSG_SQL, - MSG_INFORMATION, - MSG_NOTICE, - MSG_WARNING, - MSG_DEBUG, - MSG_ERROR, - MSG_FATALERROR + MSG_NONE, + MSG_STATUS, + MSG_SQL, + MSG_INFORMATION, + MSG_NOTICE, + MSG_WARNING, + MSG_DEBUG, + MSG_ERROR, + MSG_FATALERROR }; extern void ClearScreen(void); diff --git a/src/common/socket.c b/src/common/socket.c index d24a9c1d8..4a6e01459 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -15,35 +15,35 @@ #include #ifdef WIN32 - #include "../common/winapi.h" +#include "../common/winapi.h" #else - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #ifndef SIOCGIFCONF - #include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] - #endif - #ifndef FIONBIO - #include // FIONBIO on Solaris [FlavioJS] - #endif - - #ifdef HAVE_SETRLIMIT - #include - #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SIOCGIFCONF +#include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] +#endif +#ifndef FIONBIO +#include // FIONBIO on Solaris [FlavioJS] +#endif + +#ifdef HAVE_SETRLIMIT +#include +#endif #endif ///////////////////////////////////////////////////////////////////// #if defined(WIN32) ///////////////////////////////////////////////////////////////////// -// windows portability layer +// windows portability layer typedef int socklen_t; @@ -75,21 +75,21 @@ static int sock_arr_len = 0; /// @return Fd or -1 int sock2fd(SOCKET s) { - int fd; - - // search for the socket - for( fd = 1; fd < sock_arr_len; ++fd ) - if( sock_arr[fd] == s ) - break;// found the socket - if( fd == sock_arr_len ) - return -1;// not found - return fd; + int fd; + + // search for the socket + for (fd = 1; fd < sock_arr_len; ++fd) + if (sock_arr[fd] == s) + break;// found the socket + if (fd == sock_arr_len) + return -1;// not found + return fd; } /// Inserts the socket into the global array of sockets. /// Returns a new fd associated with the socket. -/// If there are too many sockets it closes the socket, sets an error and +/// If there are too many sockets it closes the socket, sets an error and // returns -1 instead. /// Since fd 0 is reserved, it returns values in the range [1,FD_SETSIZE[. /// @@ -97,61 +97,61 @@ int sock2fd(SOCKET s) /// @return New fd or -1 int sock2newfd(SOCKET s) { - int fd; - - // find an empty position - for( fd = 1; fd < sock_arr_len; ++fd ) - if( sock_arr[fd] == INVALID_SOCKET ) - break;// empty position - if( fd == ARRAYLENGTH(sock_arr) ) - {// too many sockets - closesocket(s); - WSASetLastError(WSAEMFILE); - return -1; - } - sock_arr[fd] = s; - if( sock_arr_len <= fd ) - sock_arr_len = fd+1; - return fd; + int fd; + + // find an empty position + for (fd = 1; fd < sock_arr_len; ++fd) + if (sock_arr[fd] == INVALID_SOCKET) + break;// empty position + if (fd == ARRAYLENGTH(sock_arr)) { + // too many sockets + closesocket(s); + WSASetLastError(WSAEMFILE); + return -1; + } + sock_arr[fd] = s; + if (sock_arr_len <= fd) + sock_arr_len = fd+1; + return fd; } -int sAccept(int fd, struct sockaddr* addr, int* addrlen) +int sAccept(int fd, struct sockaddr *addr, int *addrlen) { - SOCKET s; + SOCKET s; - // accept connection - s = accept(fd2sock(fd), addr, addrlen); - if( s == INVALID_SOCKET ) - return -1;// error - return sock2newfd(s); + // accept connection + s = accept(fd2sock(fd), addr, addrlen); + if (s == INVALID_SOCKET) + return -1;// error + return sock2newfd(s); } int sClose(int fd) { - int ret = closesocket(fd2sock(fd)); - fd2sock(fd) = INVALID_SOCKET; - return ret; + int ret = closesocket(fd2sock(fd)); + fd2sock(fd) = INVALID_SOCKET; + return ret; } int sSocket(int af, int type, int protocol) { - SOCKET s; + SOCKET s; - // create socket - s = socket(af,type,protocol); - if( s == INVALID_SOCKET ) - return -1;// error - return sock2newfd(s); + // create socket + s = socket(af,type,protocol); + if (s == INVALID_SOCKET) + return -1;// error + return sock2newfd(s); } -char* sErr(int code) +char *sErr(int code) { - static char sbuf[512]; - // strerror does not handle socket codes - if( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0 ) - snprintf(sbuf, sizeof(sbuf), "unknown error"); - return sbuf; + static char sbuf[512]; + // strerror does not handle socket codes + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0) + snprintf(sbuf, sizeof(sbuf), "unknown error"); + return sbuf; } #define sBind(fd,name,namelen) bind(fd2sock(fd),name,namelen) @@ -205,7 +205,7 @@ char* sErr(int code) ///////////////////////////////////////////////////////////////////// #ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 +#define MSG_NOSIGNAL 0 #endif fd_set readfds; @@ -230,7 +230,7 @@ static size_t socket_max_client_packet = 24576; // The connection is closed if it goes over the limit. #define WFIFO_MAX (1*1024*1024) -struct socket_data* session[FD_SETSIZE]; +struct socket_data *session[FD_SETSIZE]; #ifdef SEND_SHORTLIST int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that @@ -241,387 +241,390 @@ uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are al static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE - int ip_rules = 1; - static int connect_check(uint32 ip); +int ip_rules = 1; +static int connect_check(uint32 ip); #endif -const char* error_msg(void) +const char *error_msg(void) { - static char buf[512]; - int code = sErrno; - snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); - return buf; + static char buf[512]; + int code = sErrno; + snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); + return buf; } /*====================================== - * CORE : Default processing functions + * CORE : Default processing functions *--------------------------------------*/ -int null_recv(int fd) { return 0; } -int null_send(int fd) { return 0; } -int null_parse(int fd) { return 0; } +int null_recv(int fd) +{ + return 0; +} +int null_send(int fd) +{ + return 0; +} +int null_parse(int fd) +{ + return 0; +} ParseFunc default_func_parse = null_parse; void set_defaultparse(ParseFunc defaultparse) { - default_func_parse = defaultparse; + default_func_parse = defaultparse; } /*====================================== - * CORE : Socket options + * CORE : Socket options *--------------------------------------*/ void set_nonblocking(int fd, unsigned long yes) { - // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. - // The argp parameter is zero if nonblocking is to be disabled. - if( sIoctl(fd, FIONBIO, &yes) != 0 ) - ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); + // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. + // The argp parameter is zero if nonblocking is to be disabled. + if (sIoctl(fd, FIONBIO, &yes) != 0) + ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); } void setsocketopts(int fd) { - int yes = 1; // reuse fix + int yes = 1; // reuse fix #if !defined(WIN32) - // set SO_REAUSEADDR to true, unix only. on windows this option causes - // the previous owner of the socket to give up, which is not desirable - // in most cases, neither compatible with unix. - sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); + // set SO_REAUSEADDR to true, unix only. on windows this option causes + // the previous owner of the socket to give up, which is not desirable + // in most cases, neither compatible with unix. + sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); #ifdef SO_REUSEPORT - sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); + sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); #endif #endif - // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. - // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. - sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); - - // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) - //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) - { - struct linger opt; - opt.l_onoff = 0; // SO_DONTLINGER - opt.l_linger = 0; // Do not care - if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) ) - ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); - } + // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. + // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. + sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); + + // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) + //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) + { + struct linger opt; + opt.l_onoff = 0; // SO_DONTLINGER + opt.l_linger = 0; // Do not care + if (sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&opt, sizeof(opt))) + ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); + } } /*====================================== - * CORE : Socket Sub Function + * CORE : Socket Sub Function *--------------------------------------*/ void set_eof(int fd) { - if( session_isActive(fd) ) - { + if (session_isActive(fd)) { #ifdef SEND_SHORTLIST - // Add this socket to the shortlist for eof handling. - send_shortlist_add_fd(fd); + // Add this socket to the shortlist for eof handling. + send_shortlist_add_fd(fd); #endif - session[fd]->flag.eof = 1; - } + session[fd]->flag.eof = 1; + } } int recv_to_fifo(int fd) { - int len; - - if( !session_isActive(fd) ) - return -1; - - len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); - - if( len == SOCKET_ERROR ) - {//An exception has occured - if( sErrno != S_EWOULDBLOCK ) { - //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); - set_eof(fd); - } - return 0; - } - - if( len == 0 ) - {//Normal connection end. - set_eof(fd); - return 0; - } - - session[fd]->rdata_size += len; - session[fd]->rdata_tick = last_tick; - return 0; + int len; + + if (!session_isActive(fd)) + return -1; + + len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); + + if (len == SOCKET_ERROR) { + //An exception has occured + if (sErrno != S_EWOULDBLOCK) { + //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); + set_eof(fd); + } + return 0; + } + + if (len == 0) { + //Normal connection end. + set_eof(fd); + return 0; + } + + session[fd]->rdata_size += len; + session[fd]->rdata_tick = last_tick; + return 0; } int send_from_fifo(int fd) { - int len; + int len; - if( !session_isValid(fd) ) - return -1; + if (!session_isValid(fd)) + return -1; - if( session[fd]->wdata_size == 0 ) - return 0; // nothing to send + if (session[fd]->wdata_size == 0) + return 0; // nothing to send - len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); + len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); - if( len == SOCKET_ERROR ) - {//An exception has occured - if( sErrno != S_EWOULDBLOCK ) { - //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); - session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] - set_eof(fd); - } - return 0; - } + if (len == SOCKET_ERROR) { + //An exception has occured + if (sErrno != S_EWOULDBLOCK) { + //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); + session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] + set_eof(fd); + } + return 0; + } - if( len > 0 ) - { - // some data could not be transferred? - // shift unsent data to the beginning of the queue - if( (size_t)len < session[fd]->wdata_size ) - memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); + if (len > 0) { + // some data could not be transferred? + // shift unsent data to the beginning of the queue + if ((size_t)len < session[fd]->wdata_size) + memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); - session[fd]->wdata_size -= len; - } + session[fd]->wdata_size -= len; + } - return 0; + return 0; } /// Best effort - there's no warranty that the data will be sent. void flush_fifo(int fd) { - if(session[fd] != NULL) - session[fd]->func_send(fd); + if (session[fd] != NULL) + session[fd]->func_send(fd); } void flush_fifos(void) { - int i; - for(i = 1; i < fd_max; i++) - flush_fifo(i); + int i; + for (i = 1; i < fd_max; i++) + flush_fifo(i); } /*====================================== - * CORE : Connection functions + * CORE : Connection functions *--------------------------------------*/ int connect_client(int listen_fd) { - int fd; - struct sockaddr_in client_address; - socklen_t len; - - len = sizeof(client_address); - - fd = sAccept(listen_fd, (struct sockaddr*)&client_address, &len); - if ( fd == -1 ) { - ShowError("connect_client: accept failed (%s)!\n", error_msg()); - return -1; - } - if( fd == 0 ) - {// reserved - ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); + int fd; + struct sockaddr_in client_address; + socklen_t len; + + len = sizeof(client_address); + + fd = sAccept(listen_fd, (struct sockaddr *)&client_address, &len); + if (fd == -1) { + ShowError("connect_client: accept failed (%s)!\n", error_msg()); + return -1; + } + if (fd == 0) { + // reserved + ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); #ifndef MINICORE - if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) { - do_close(fd); - return -1; - } + if (ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr))) { + do_close(fd); + return -1; + } #endif - if( fd_max <= fd ) fd_max = fd + 1; - sFD_SET(fd,&readfds); + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd,&readfds); - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); - return fd; + return fd; } int make_listen_bind(uint32 ip, uint16 port) { - struct sockaddr_in server_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if( fd == -1 ) - { - ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); - exit(EXIT_FAILURE); - } - if( fd == 0 ) - {// reserved - ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl(ip); - server_address.sin_port = htons(port); - - result = sBind(fd, (struct sockaddr*)&server_address, sizeof(server_address)); - if( result == SOCKET_ERROR ) { - ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - result = sListen(fd,5); - if( result == SOCKET_ERROR ) { - ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - - if(fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd, &readfds); - - create_session(fd, connect_client, null_send, null_parse); - session[fd]->client_addr = 0; // just listens - session[fd]->rdata_tick = 0; // disable timeouts on this socket - - return fd; + struct sockaddr_in server_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); + exit(EXIT_FAILURE); + } + if (fd == 0) { + // reserved + ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl(ip); + server_address.sin_port = htons(port); + + result = sBind(fd, (struct sockaddr *)&server_address, sizeof(server_address)); + if (result == SOCKET_ERROR) { + ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + result = sListen(fd,5); + if (result == SOCKET_ERROR) { + ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd, &readfds); + + create_session(fd, connect_client, null_send, null_parse); + session[fd]->client_addr = 0; // just listens + session[fd]->rdata_tick = 0; // disable timeouts on this socket + + return fd; } -int make_connection(uint32 ip, uint16 port, bool silent) { - struct sockaddr_in remote_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if (fd == -1) { - ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); - return -1; - } - if( fd == 0 ) - {// reserved - ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - - remote_address.sin_family = AF_INET; - remote_address.sin_addr.s_addr = htonl(ip); - remote_address.sin_port = htons(port); - - if( !silent ) - ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); - - result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); - if( result == SOCKET_ERROR ) { - if( !silent ) - ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); - do_close(fd); - return -1; - } - //Now the socket can be made non-blocking. [Skotlex] - set_nonblocking(fd, 1); - - if (fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd,&readfds); - - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); - - return fd; +int make_connection(uint32 ip, uint16 port, bool silent) +{ + struct sockaddr_in remote_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); + return -1; + } + if (fd == 0) { + // reserved + ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + + remote_address.sin_family = AF_INET; + remote_address.sin_addr.s_addr = htonl(ip); + remote_address.sin_port = htons(port); + + if (!silent) + ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); + + result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); + if (result == SOCKET_ERROR) { + if (!silent) + ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); + do_close(fd); + return -1; + } + //Now the socket can be made non-blocking. [Skotlex] + set_nonblocking(fd, 1); + + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd,&readfds); + + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); + + return fd; } static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse) { - CREATE(session[fd], struct socket_data, 1); - CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); - CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = func_recv; - session[fd]->func_send = func_send; - session[fd]->func_parse = func_parse; - session[fd]->rdata_tick = last_tick; - return 0; + CREATE(session[fd], struct socket_data, 1); + CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); + CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = func_recv; + session[fd]->func_send = func_send; + session[fd]->func_parse = func_parse; + session[fd]->rdata_tick = last_tick; + return 0; } static void delete_session(int fd) { - if( session_isValid(fd) ) - { - aFree(session[fd]->rdata); - aFree(session[fd]->wdata); - aFree(session[fd]->session_data); - aFree(session[fd]); - session[fd] = NULL; - } + if (session_isValid(fd)) { + aFree(session[fd]->rdata); + aFree(session[fd]->wdata); + aFree(session[fd]->session_data); + aFree(session[fd]); + session[fd] = NULL; + } } int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size) { - if( !session_isValid(fd) ) - return 0; - - if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { - RECREATE(session[fd]->rdata, unsigned char, rfifo_size); - session[fd]->max_rdata = rfifo_size; - } - - if( session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { - RECREATE(session[fd]->wdata, unsigned char, wfifo_size); - session[fd]->max_wdata = wfifo_size; - } - return 0; + if (!session_isValid(fd)) + return 0; + + if (session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { + RECREATE(session[fd]->rdata, unsigned char, rfifo_size); + session[fd]->max_rdata = rfifo_size; + } + + if (session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { + RECREATE(session[fd]->wdata, unsigned char, wfifo_size); + session[fd]->max_wdata = wfifo_size; + } + return 0; } int realloc_writefifo(int fd, size_t addition) { - size_t newsize; - - if( !session_isValid(fd) ) // might not happen - return 0; - - if( session[fd]->wdata_size + addition > session[fd]->max_wdata ) - { // grow rule; grow in multiples of WFIFO_SIZE - newsize = WFIFO_SIZE; - while( session[fd]->wdata_size + addition > newsize ) newsize += WFIFO_SIZE; - } - else - if( session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) - && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata ) - { // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. - newsize = session[fd]->max_wdata / 2; - } - else // no change - return 0; - - RECREATE(session[fd]->wdata, unsigned char, newsize); - session[fd]->max_wdata = newsize; - - return 0; + size_t newsize; + + if (!session_isValid(fd)) // might not happen + return 0; + + if (session[fd]->wdata_size + addition > session[fd]->max_wdata) { + // grow rule; grow in multiples of WFIFO_SIZE + newsize = WFIFO_SIZE; + while (session[fd]->wdata_size + addition > newsize) newsize += WFIFO_SIZE; + } else if (session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) + && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata) { + // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. + newsize = session[fd]->max_wdata / 2; + } else // no change + return 0; + + RECREATE(session[fd]->wdata, unsigned char, newsize); + session[fd]->max_wdata = newsize; + + return 0; } /// advance the RFIFO cursor (marking 'len' bytes as processed) @@ -629,197 +632,186 @@ int RFIFOSKIP(int fd, size_t len) { struct socket_data *s; - if ( !session_isActive(fd) ) - return 0; + if (!session_isActive(fd)) + return 0; - s = session[fd]; + s = session[fd]; - if ( s->rdata_size < s->rdata_pos + len ) { - ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); - len = RFIFOREST(fd); - } + if (s->rdata_size < s->rdata_pos + len) { + ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); + len = RFIFOREST(fd); + } - s->rdata_pos = s->rdata_pos + len; - return 0; + s->rdata_pos = s->rdata_pos + len; + return 0; } /// advance the WFIFO cursor (marking 'len' bytes for sending) int WFIFOSET(int fd, size_t len) { - size_t newreserve; - struct socket_data* s = session[fd]; - - if( !session_isValid(fd) || s->wdata == NULL ) - return 0; - - // we have written len bytes to the buffer already before calling WFIFOSET - if(s->wdata_size+len > s->max_wdata) - { // actually there was a buffer overflow already - uint32 ip = s->client_addr; - ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); - ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16*)(s->wdata + s->wdata_size))); - // no other chance, make a better fifo model - exit(EXIT_FAILURE); - } - - if( len > 0xFFFF ) - { - // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) - // all known fixed-size packets are within this limit, so use the same limit - ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); - exit(EXIT_FAILURE); - } - else if( len == 0 ) - { - // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote - // the packet type into memory, even if it could have overwritten vital data - // this can happen when a new packet was added on map-server, but packet len table was not updated - ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); - return 0; - } - - if( !s->flag.server ) { - - if( len > socket_max_client_packet ) {// see declaration of socket_max_client_packet for details - ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); - return 0; - } - - if( s->wdata_size+len > WFIFO_MAX ) {// reached maximum write fifo size - ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); - set_eof(fd); - return 0; - } - - } - s->wdata_size += len; - //If the interserver has 200% of its normal size full, flush the data. - if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK ) - flush_fifo(fd); - - // always keep a WFIFO_SIZE reserve in the buffer - // For inter-server connections, let the reserve be 1/4th of the link size. - newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; - - // readjust the buffer to include the chosen reserve - realloc_writefifo(fd, newreserve); + size_t newreserve; + struct socket_data *s = session[fd]; + + if (!session_isValid(fd) || s->wdata == NULL) + return 0; + + // we have written len bytes to the buffer already before calling WFIFOSET + if (s->wdata_size+len > s->max_wdata) { + // actually there was a buffer overflow already + uint32 ip = s->client_addr; + ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); + ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16 *)(s->wdata + s->wdata_size))); + // no other chance, make a better fifo model + exit(EXIT_FAILURE); + } + + if (len > 0xFFFF) { + // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) + // all known fixed-size packets are within this limit, so use the same limit + ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16 *)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); + exit(EXIT_FAILURE); + } else if (len == 0) { + // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote + // the packet type into memory, even if it could have overwritten vital data + // this can happen when a new packet was added on map-server, but packet len table was not updated + ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); + return 0; + } + + if (!s->flag.server) { + + if (len > socket_max_client_packet) { // see declaration of socket_max_client_packet for details + ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); + return 0; + } + + if (s->wdata_size+len > WFIFO_MAX) { // reached maximum write fifo size + ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); + set_eof(fd); + return 0; + } + + } + s->wdata_size += len; + //If the interserver has 200% of its normal size full, flush the data. + if (s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK) + flush_fifo(fd); + + // always keep a WFIFO_SIZE reserve in the buffer + // For inter-server connections, let the reserve be 1/4th of the link size. + newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; + + // readjust the buffer to include the chosen reserve + realloc_writefifo(fd, newreserve); #ifdef SEND_SHORTLIST - send_shortlist_add_fd(fd); + send_shortlist_add_fd(fd); #endif - return 0; + return 0; } int do_sockets(int next) { - fd_set rfd; - struct timeval timeout; - int ret,i; + fd_set rfd; + struct timeval timeout; + int ret,i; - // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. - // Send remaining data and process client-side disconnects here. + // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. + // Send remaining data and process client-side disconnects here. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if(session[i]->wdata_size) - session[i]->func_send(i); - } + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->wdata_size) + session[i]->func_send(i); + } #endif - // can timeout until the next tick - timeout.tv_sec = next/1000; - timeout.tv_usec = next%1000*1000; + // can timeout until the next tick + timeout.tv_sec = next/1000; + timeout.tv_usec = next%1000*1000; - memcpy(&rfd, &readfds, sizeof(rfd)); - ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); + memcpy(&rfd, &readfds, sizeof(rfd)); + ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); - if( ret == SOCKET_ERROR ) - { - if( sErrno != S_EINTR ) - { - ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); - exit(EXIT_FAILURE); - } - return 0; // interrupted by a signal, just loop and try again - } + if (ret == SOCKET_ERROR) { + if (sErrno != S_EINTR) { + ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); + exit(EXIT_FAILURE); + } + return 0; // interrupted by a signal, just loop and try again + } - last_tick = time(NULL); + last_tick = time(NULL); #if defined(WIN32) - // on windows, enumerating all members of the fd_set is way faster if we access the internals - for( i = 0; i < (int)rfd.fd_count; ++i ) - { - int fd = sock2fd(rfd.fd_array[i]); - if( session[fd] ) - session[fd]->func_recv(fd); - } + // on windows, enumerating all members of the fd_set is way faster if we access the internals + for (i = 0; i < (int)rfd.fd_count; ++i) { + int fd = sock2fd(rfd.fd_array[i]); + if (session[fd]) + session[fd]->func_recv(fd); + } #else - // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way - for( i = 1; ret && i < fd_max; ++i ) - { - if(sFD_ISSET(i,&rfd) && session[i]) - { - session[i]->func_recv(i); - --ret; - } - } + // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way + for (i = 1; ret && i < fd_max; ++i) { + if (sFD_ISSET(i,&rfd) && session[i]) { + session[i]->func_recv(i); + --ret; + } + } #endif - // POSTSEND Send remaining data and handle eof sessions. + // POSTSEND Send remaining data and handle eof sessions. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if(session[i]->wdata_size) - session[i]->func_send(i); - - if(session[i]->flag.eof) //func_send can't free a session, this is safe. - { //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] - session[i]->func_parse(i); //This should close the session immediately. - } - } + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->wdata_size) + session[i]->func_send(i); + + if (session[i]->flag.eof) { //func_send can't free a session, this is safe. + //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] + session[i]->func_parse(i); //This should close the session immediately. + } + } #endif - // parse input data on each socket - for(i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { - if( session[i]->flag.server ) {/* server is special */ - if( session[i]->flag.ping != 2 )/* only update if necessary otherwise it'd resend the ping unnecessarily */ - session[i]->flag.ping = 1; - } else { - ShowInfo("Session #%d timed out\n", i); - set_eof(i); - } - } - - session[i]->func_parse(i); - - if(!session[i]) - continue; - - // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) - if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { - set_eof(i); - continue; - } - RFIFOFLUSH(i); - } - - return 0; + // parse input data on each socket + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { + if (session[i]->flag.server) { /* server is special */ + if (session[i]->flag.ping != 2) /* only update if necessary otherwise it'd resend the ping unnecessarily */ + session[i]->flag.ping = 1; + } else { + ShowInfo("Session #%d timed out\n", i); + set_eof(i); + } + } + + session[i]->func_parse(i); + + if (!session[i]) + continue; + + // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) + if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { + set_eof(i); + continue; + } + RFIFOFLUSH(i); + } + + return 0; } ////////////////////////////// @@ -828,26 +820,26 @@ int do_sockets(int next) // IP rules and DDoS protection typedef struct _connect_history { - struct _connect_history* next; - uint32 ip; - uint32 tick; - int count; - unsigned ddos : 1; + struct _connect_history *next; + uint32 ip; + uint32 tick; + int count; + unsigned ddos : 1; } ConnectHistory; typedef struct _access_control { - uint32 ip; - uint32 mask; + uint32 ip; + uint32 mask; } AccessControl; enum _aco { - ACO_DENY_ALLOW, - ACO_ALLOW_DENY, - ACO_MUTUAL_FAILURE + ACO_DENY_ALLOW, + ACO_ALLOW_DENY, + ACO_MUTUAL_FAILURE }; -static AccessControl* access_allow = NULL; -static AccessControl* access_deny = NULL; +static AccessControl *access_allow = NULL; +static AccessControl *access_deny = NULL; static int access_order = ACO_DENY_ALLOW; static int access_allownum = 0; static int access_denynum = 0; @@ -857,7 +849,7 @@ static int ddos_interval = 3*1000; static int ddos_autoreset = 10*60*1000; /// Connection history, an array of linked lists. /// The array's index for any ip is ip&0xFFFF -static ConnectHistory* connect_history[0x10000]; +static ConnectHistory *connect_history[0x10000]; static int connect_check_(uint32 ip); @@ -865,11 +857,11 @@ static int connect_check_(uint32 ip); /// @see connect_check_() static int connect_check(uint32 ip) { - int result = connect_check_(ip); - if( access_debug ) { - ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); - } - return result; + int result = connect_check_(ip); + if (access_debug) { + ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); + } + return result; } /// Verifies if the IP can connect. @@ -877,504 +869,494 @@ static int connect_check(uint32 ip) /// 1 or 2 : Connection Accepted static int connect_check_(uint32 ip) { - ConnectHistory* hist = connect_history[ip&0xFFFF]; - int i; - int is_allowip = 0; - int is_denyip = 0; - int connect_ok = 0; - - // Search the allow list - for( i=0; i < access_allownum; ++i ){ - if( (ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask) ){ - if( access_debug ){ - ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_allow[i].ip), - CONVIP(access_allow[i].mask)); - } - is_allowip = 1; - break; - } - } - // Search the deny list - for( i=0; i < access_denynum; ++i ){ - if( (ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask) ){ - if( access_debug ){ - ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_deny[i].ip), - CONVIP(access_deny[i].mask)); - } - is_denyip = 1; - break; - } - } - // Decide connection status - // 0 : Reject - // 1 : Accept - // 2 : Unconditional Accept (accepts even if flagged as DDoS) - switch(access_order) { - case ACO_DENY_ALLOW: - default: - if( is_denyip ) - connect_ok = 0; // Reject - else if( is_allowip ) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 1; // Accept - break; - case ACO_ALLOW_DENY: - if( is_allowip ) - connect_ok = 2; // Unconditional Accept - else if( is_denyip ) - connect_ok = 0; // Reject - else - connect_ok = 1; // Accept - break; - case ACO_MUTUAL_FAILURE: - if( is_allowip && !is_denyip ) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 0; // Reject - break; - } - - // Inspect connection history - while( hist ) { - if( ip == hist->ip ) - {// IP found - if( hist->ddos ) - {// flagged as DDoS - return (connect_ok == 2 ? 1 : 0); - } else if( DIFF_TICK(gettick(),hist->tick) < ddos_interval ) - {// connection within ddos_interval - hist->tick = gettick(); - if( hist->count++ >= ddos_count ) - {// DDoS attack detected - hist->ddos = 1; - ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); - return (connect_ok == 2 ? 1 : 0); - } - return connect_ok; - } else - {// not within ddos_interval, clear data - hist->tick = gettick(); - hist->count = 0; - return connect_ok; - } - } - hist = hist->next; - } - // IP not found, add to history - CREATE(hist, ConnectHistory, 1); - memset(hist, 0, sizeof(ConnectHistory)); - hist->ip = ip; - hist->tick = gettick(); - hist->next = connect_history[ip&0xFFFF]; - connect_history[ip&0xFFFF] = hist; - return connect_ok; + ConnectHistory *hist = connect_history[ip&0xFFFF]; + int i; + int is_allowip = 0; + int is_denyip = 0; + int connect_ok = 0; + + // Search the allow list + for (i=0; i < access_allownum; ++i) { + if ((ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask)) { + if (access_debug) { + ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_allow[i].ip), + CONVIP(access_allow[i].mask)); + } + is_allowip = 1; + break; + } + } + // Search the deny list + for (i=0; i < access_denynum; ++i) { + if ((ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask)) { + if (access_debug) { + ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_deny[i].ip), + CONVIP(access_deny[i].mask)); + } + is_denyip = 1; + break; + } + } + // Decide connection status + // 0 : Reject + // 1 : Accept + // 2 : Unconditional Accept (accepts even if flagged as DDoS) + switch (access_order) { + case ACO_DENY_ALLOW: + default: + if (is_denyip) + connect_ok = 0; // Reject + else if (is_allowip) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 1; // Accept + break; + case ACO_ALLOW_DENY: + if (is_allowip) + connect_ok = 2; // Unconditional Accept + else if (is_denyip) + connect_ok = 0; // Reject + else + connect_ok = 1; // Accept + break; + case ACO_MUTUAL_FAILURE: + if (is_allowip && !is_denyip) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 0; // Reject + break; + } + + // Inspect connection history + while (hist) { + if (ip == hist->ip) { + // IP found + if (hist->ddos) { + // flagged as DDoS + return (connect_ok == 2 ? 1 : 0); + } else if (DIFF_TICK(gettick(),hist->tick) < ddos_interval) { + // connection within ddos_interval + hist->tick = gettick(); + if (hist->count++ >= ddos_count) { + // DDoS attack detected + hist->ddos = 1; + ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); + return (connect_ok == 2 ? 1 : 0); + } + return connect_ok; + } else { + // not within ddos_interval, clear data + hist->tick = gettick(); + hist->count = 0; + return connect_ok; + } + } + hist = hist->next; + } + // IP not found, add to history + CREATE(hist, ConnectHistory, 1); + memset(hist, 0, sizeof(ConnectHistory)); + hist->ip = ip; + hist->tick = gettick(); + hist->next = connect_history[ip&0xFFFF]; + connect_history[ip&0xFFFF] = hist; + return connect_ok; } /// Timer function. /// Deletes old connection history records. static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data) { - int i; - int clear = 0; - int list = 0; - ConnectHistory root; - ConnectHistory* prev_hist; - ConnectHistory* hist; - - for( i=0; i < 0x10000 ; ++i ){ - prev_hist = &root; - root.next = hist = connect_history[i]; - while( hist ){ - if( (!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || - (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset) ) - {// Remove connection history - prev_hist->next = hist->next; - aFree(hist); - hist = prev_hist->next; - clear++; - } else { - prev_hist = hist; - hist = hist->next; - } - list++; - } - connect_history[i] = root.next; - } - if( access_debug ){ - ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); - } - return list; + int i; + int clear = 0; + int list = 0; + ConnectHistory root; + ConnectHistory *prev_hist; + ConnectHistory *hist; + + for (i=0; i < 0x10000 ; ++i) { + prev_hist = &root; + root.next = hist = connect_history[i]; + while (hist) { + if ((!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || + (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset)) { + // Remove connection history + prev_hist->next = hist->next; + aFree(hist); + hist = prev_hist->next; + clear++; + } else { + prev_hist = hist; + hist = hist->next; + } + list++; + } + connect_history[i] = root.next; + } + if (access_debug) { + ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); + } + return list; } /// Parses the ip address and mask and puts it into acc. /// Returns 1 is successful, 0 otherwise. -int access_ipmask(const char* str, AccessControl* acc) +int access_ipmask(const char *str, AccessControl *acc) { - uint32 ip; - uint32 mask; - unsigned int a[4]; - unsigned int m[4]; - int n; - - if( strcmp(str,"all") == 0 ) { - ip = 0; - mask = 0; - } else { - if( ((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask - (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask - (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4 ) || // not an ip - a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip - (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask - (n == 5 && m[0] > 32) ){ // invalid bit mask - return 0; - } - ip = MAKEIP(a[0],a[1],a[2],a[3]); - if( n == 8 ) - {// standard mask - mask = MAKEIP(m[0],m[1],m[2],m[3]); - } else if( n == 5 ) - {// bit mask - mask = 0; - while( m[0] ){ - mask = (mask >> 1) | 0x80000000; - --m[0]; - } - } else - {// just this ip - mask = 0xFFFFFFFF; - } - } - if( access_debug ){ - ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); - } - acc->ip = ip; - acc->mask = mask; - return 1; + uint32 ip; + uint32 mask; + unsigned int a[4]; + unsigned int m[4]; + int n; + + if (strcmp(str,"all") == 0) { + ip = 0; + mask = 0; + } else { + if (((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask + (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask + (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4) || // not an ip + a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip + (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask + (n == 5 && m[0] > 32)) { // invalid bit mask + return 0; + } + ip = MAKEIP(a[0],a[1],a[2],a[3]); + if (n == 8) { + // standard mask + mask = MAKEIP(m[0],m[1],m[2],m[3]); + } else if (n == 5) { + // bit mask + mask = 0; + while (m[0]) { + mask = (mask >> 1) | 0x80000000; + --m[0]; + } + } else { + // just this ip + mask = 0xFFFFFFFF; + } + } + if (access_debug) { + ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); + } + acc->ip = ip; + acc->mask = mask; + return 1; } ////////////////////////////// #endif ////////////////////////////// -int socket_config_read(const char* cfgName) +int socket_config_read(const char *cfgName) { - char line[1024],w1[1024],w2[1024]; - FILE *fp; - - fp = fopen(cfgName, "r"); - if(fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if(sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (!strcmpi(w1, "stall_time")) { - stall_time = atoi(w2); - if( stall_time < 3 ) - stall_time = 3;/* a minimum is required to refrain it from killing itself */ - } + char line[1024],w1[1024],w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (!strcmpi(w1, "stall_time")) { + stall_time = atoi(w2); + if (stall_time < 3) + stall_time = 3;/* a minimum is required to refrain it from killing itself */ + } #ifndef MINICORE - else if (!strcmpi(w1, "enable_ip_rules")) { - ip_rules = config_switch(w2); - } else if (!strcmpi(w1, "order")) { - if (!strcmpi(w2, "deny,allow")) - access_order = ACO_DENY_ALLOW; - else if (!strcmpi(w2, "allow,deny")) - access_order = ACO_ALLOW_DENY; - else if (!strcmpi(w2, "mutual-failure")) - access_order = ACO_MUTUAL_FAILURE; - } else if (!strcmpi(w1, "allow")) { - RECREATE(access_allow, AccessControl, access_allownum+1); - if (access_ipmask(w2, &access_allow[access_allownum])) - ++access_allownum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } else if (!strcmpi(w1, "deny")) { - RECREATE(access_deny, AccessControl, access_denynum+1); - if (access_ipmask(w2, &access_deny[access_denynum])) - ++access_denynum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } - else if (!strcmpi(w1,"ddos_interval")) - ddos_interval = atoi(w2); - else if (!strcmpi(w1,"ddos_count")) - ddos_count = atoi(w2); - else if (!strcmpi(w1,"ddos_autoreset")) - ddos_autoreset = atoi(w2); - else if (!strcmpi(w1,"debug")) - access_debug = config_switch(w2); - else if (!strcmpi(w1,"socket_max_client_packet")) - socket_max_client_packet = strtoul(w2, NULL, 0); + else if (!strcmpi(w1, "enable_ip_rules")) { + ip_rules = config_switch(w2); + } else if (!strcmpi(w1, "order")) { + if (!strcmpi(w2, "deny,allow")) + access_order = ACO_DENY_ALLOW; + else if (!strcmpi(w2, "allow,deny")) + access_order = ACO_ALLOW_DENY; + else if (!strcmpi(w2, "mutual-failure")) + access_order = ACO_MUTUAL_FAILURE; + } else if (!strcmpi(w1, "allow")) { + RECREATE(access_allow, AccessControl, access_allownum+1); + if (access_ipmask(w2, &access_allow[access_allownum])) + ++access_allownum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } else if (!strcmpi(w1, "deny")) { + RECREATE(access_deny, AccessControl, access_denynum+1); + if (access_ipmask(w2, &access_deny[access_denynum])) + ++access_denynum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } else if (!strcmpi(w1,"ddos_interval")) + ddos_interval = atoi(w2); + else if (!strcmpi(w1,"ddos_count")) + ddos_count = atoi(w2); + else if (!strcmpi(w1,"ddos_autoreset")) + ddos_autoreset = atoi(w2); + else if (!strcmpi(w1,"debug")) + access_debug = config_switch(w2); + else if (!strcmpi(w1,"socket_max_client_packet")) + socket_max_client_packet = strtoul(w2, NULL, 0); #endif - else if (!strcmpi(w1, "import")) - socket_config_read(w2); - else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); - } - - fclose(fp); - return 0; + else if (!strcmpi(w1, "import")) + socket_config_read(w2); + else + ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + } + + fclose(fp); + return 0; } void socket_final(void) { - int i; + int i; #ifndef MINICORE - ConnectHistory* hist; - ConnectHistory* next_hist; - - for( i=0; i < 0x10000; ++i ){ - hist = connect_history[i]; - while( hist ){ - next_hist = hist->next; - aFree(hist); - hist = next_hist; - } - } - if( access_allow ) - aFree(access_allow); - if( access_deny ) - aFree(access_deny); + ConnectHistory *hist; + ConnectHistory *next_hist; + + for (i=0; i < 0x10000; ++i) { + hist = connect_history[i]; + while (hist) { + next_hist = hist->next; + aFree(hist); + hist = next_hist; + } + } + if (access_allow) + aFree(access_allow); + if (access_deny) + aFree(access_deny); #endif - for( i = 1; i < fd_max; i++ ) - if(session[i]) - do_close(i); + for (i = 1; i < fd_max; i++) + if (session[i]) + do_close(i); - // session[0] のダミーデータを削除 - aFree(session[0]->rdata); - aFree(session[0]->wdata); - aFree(session[0]); + // session[0] のダミーデータを削除 + aFree(session[0]->rdata); + aFree(session[0]->wdata); + aFree(session[0]); } /// Closes a socket. void do_close(int fd) { - if( fd <= 0 ||fd >= FD_SETSIZE ) - return;// invalid - - flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) - sFD_CLR(fd, &readfds);// this needs to be done before closing the socket - sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes - sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. - if (session[fd]) delete_session(fd); + if (fd <= 0 ||fd >= FD_SETSIZE) + return;// invalid + + flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) + sFD_CLR(fd, &readfds);// this needs to be done before closing the socket + sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes + sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. + if (session[fd]) delete_session(fd); } /// Retrieve local ips in host byte order. /// Uses loopback is no address is found. -int socket_getips(uint32* ips, int max) +int socket_getips(uint32 *ips, int max) { - int num = 0; + int num = 0; - if( ips == NULL || max <= 0 ) - return 0; + if (ips == NULL || max <= 0) + return 0; #ifdef WIN32 - { - char fullhost[255]; - u_long** a; - struct hostent* hent; - - // XXX This should look up the local IP addresses in the registry - // instead of calling gethostbyname. However, the way IP addresses - // are stored in the registry is annoyingly complex, so I'll leave - // this as T.B.D. [Meruru] - if( gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR ) - { - ShowError("socket_getips: No hostname defined!\n"); - return 0; - } - else - { - hent = gethostbyname(fullhost); - if( hent == NULL ){ - ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); - return 0; - } - a = (u_long**)hent->h_addr_list; - for( ; a[num] != NULL && num < max; ++num) - ips[num] = (uint32)ntohl(*a[num]); - } - } + { + char fullhost[255]; + u_long **a; + struct hostent *hent; + + // XXX This should look up the local IP addresses in the registry + // instead of calling gethostbyname. However, the way IP addresses + // are stored in the registry is annoyingly complex, so I'll leave + // this as T.B.D. [Meruru] + if (gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR) { + ShowError("socket_getips: No hostname defined!\n"); + return 0; + } else { + hent = gethostbyname(fullhost); + if (hent == NULL) { + ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); + return 0; + } + a = (u_long **)hent->h_addr_list; + for (; a[num] != NULL && num < max; ++num) + ips[num] = (uint32)ntohl(*a[num]); + } + } #else // not WIN32 - { - int pos; - int fd; - char buf[2*16*sizeof(struct ifreq)]; - struct ifconf ic; - struct ifreq* ir; - struct sockaddr_in* a; - u_long ad; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - memset(buf, 0x00, sizeof(buf)); - - // The ioctl call will fail with Invalid Argument if there are more - // interfaces than will fit in the buffer - ic.ifc_len = sizeof(buf); - ic.ifc_buf = buf; - if( sIoctl(fd, SIOCGIFCONF, &ic) == -1 ) - { - ShowError("socket_getips: SIOCGIFCONF failed!\n"); - return 0; - } - else - { - for( pos=0; pos < ic.ifc_len && num < max; ) - { - ir = (struct ifreq*)(buf+pos); - a = (struct sockaddr_in*) &(ir->ifr_addr); - if( a->sin_family == AF_INET ){ - ad = ntohl(a->sin_addr.s_addr); - if( ad != INADDR_LOOPBACK && ad != INADDR_ANY ) - ips[num++] = (uint32)ad; - } - #if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) - pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); - #else// not AIX or APPLE - pos += sizeof(struct ifreq); - #endif//not AIX or APPLE - } - } - sClose(fd); - } + { + int pos; + int fd; + char buf[2*16*sizeof(struct ifreq)]; + struct ifconf ic; + struct ifreq *ir; + struct sockaddr_in *a; + u_long ad; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + memset(buf, 0x00, sizeof(buf)); + + // The ioctl call will fail with Invalid Argument if there are more + // interfaces than will fit in the buffer + ic.ifc_len = sizeof(buf); + ic.ifc_buf = buf; + if (sIoctl(fd, SIOCGIFCONF, &ic) == -1) { + ShowError("socket_getips: SIOCGIFCONF failed!\n"); + return 0; + } else { + for (pos=0; pos < ic.ifc_len && num < max;) { + ir = (struct ifreq *)(buf+pos); + a = (struct sockaddr_in *) &(ir->ifr_addr); + if (a->sin_family == AF_INET) { + ad = ntohl(a->sin_addr.s_addr); + if (ad != INADDR_LOOPBACK && ad != INADDR_ANY) + ips[num++] = (uint32)ad; + } +#if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) + pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); +#else// not AIX or APPLE + pos += sizeof(struct ifreq); +#endif//not AIX or APPLE + } + } + sClose(fd); + } #endif // not W32 - // Use loopback if no ips are found - if( num == 0 ) - ips[num++] = (uint32)INADDR_LOOPBACK; + // Use loopback if no ips are found + if (num == 0) + ips[num++] = (uint32)INADDR_LOOPBACK; - return num; + return num; } void socket_init(void) { - char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; - unsigned int rlim_cur = FD_SETSIZE; + char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; + unsigned int rlim_cur = FD_SETSIZE; #ifdef WIN32 - {// Start up windows networking - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 0); - if( WSAStartup(wVersionRequested, &wsaData) != 0 ) - { - ShowError("socket_init: WinSock not available!\n"); - return; - } - if( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 ) - { - ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); - return; - } - } + { + // Start up windows networking + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + ShowError("socket_init: WinSock not available!\n"); + return; + } + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { + ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); + return; + } + } #elif defined(HAVE_SETRLIMIT) && !defined(CYGWIN) - // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. - // "Number of fds is virtually unlimited in cygwin" (sys/param.h) - {// set socket limit to FD_SETSIZE - struct rlimit rlp; - if( 0 == getrlimit(RLIMIT_NOFILE, &rlp) ) - { - rlp.rlim_cur = FD_SETSIZE; - if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) - {// failed, try setting the maximum too (permission to change system limits is required) - rlp.rlim_max = FD_SETSIZE; - if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) - {// failed - const char *errmsg = error_msg(); - int rlim_ori; - // set to maximum allowed - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_ori = (int)rlp.rlim_cur; - rlp.rlim_cur = rlp.rlim_max; - setrlimit(RLIMIT_NOFILE, &rlp); - // report limit - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_cur = rlp.rlim_cur; - ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); - } - } - } - } + // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. + // "Number of fds is virtually unlimited in cygwin" (sys/param.h) + { + // set socket limit to FD_SETSIZE + struct rlimit rlp; + if (0 == getrlimit(RLIMIT_NOFILE, &rlp)) { + rlp.rlim_cur = FD_SETSIZE; + if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { + // failed, try setting the maximum too (permission to change system limits is required) + rlp.rlim_max = FD_SETSIZE; + if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { + // failed + const char *errmsg = error_msg(); + int rlim_ori; + // set to maximum allowed + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_ori = (int)rlp.rlim_cur; + rlp.rlim_cur = rlp.rlim_max; + setrlimit(RLIMIT_NOFILE, &rlp); + // report limit + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_cur = rlp.rlim_cur; + ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); + } + } + } + } #endif - // Get initial local ips - naddr_ = socket_getips(addr_,16); + // Get initial local ips + naddr_ = socket_getips(addr_,16); - sFD_ZERO(&readfds); + sFD_ZERO(&readfds); #if defined(SEND_SHORTLIST) - memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); + memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); #endif - socket_config_read(SOCKET_CONF_FILENAME); + socket_config_read(SOCKET_CONF_FILENAME); - // initialise last send-receive tick - last_tick = time(NULL); + // initialise last send-receive tick + last_tick = time(NULL); - // session[0] is now currently used for disconnected sessions of the map server, and as such, - // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] - create_session(0, null_recv, null_send, null_parse); + // session[0] is now currently used for disconnected sessions of the map server, and as such, + // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] + create_session(0, null_recv, null_send, null_parse); #ifndef MINICORE - // Delete old connection history every 5 minutes - memset(connect_history, 0, sizeof(connect_history)); - add_timer_func_list(connect_check_clear, "connect_check_clear"); - add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); + // Delete old connection history every 5 minutes + memset(connect_history, 0, sizeof(connect_history)); + add_timer_func_list(connect_check_clear, "connect_check_clear"); + add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); #endif - ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); + ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); } bool session_isValid(int fd) { - return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL ); + return (fd > 0 && fd < FD_SETSIZE && session[fd] != NULL); } bool session_isActive(int fd) { - return ( session_isValid(fd) && !session[fd]->flag.eof ); + return (session_isValid(fd) && !session[fd]->flag.eof); } // Resolves hostname into a numeric ip. -uint32 host2ip(const char* hostname) +uint32 host2ip(const char *hostname) { - struct hostent* h = gethostbyname(hostname); - return (h != NULL) ? ntohl(*(uint32*)h->h_addr) : 0; + struct hostent *h = gethostbyname(hostname); + return (h != NULL) ? ntohl(*(uint32 *)h->h_addr) : 0; } // Converts a numeric ip into a dot-formatted string. // Result is placed either into a user-provided buffer or a static system buffer. -const char* ip2str(uint32 ip, char ip_str[16]) +const char *ip2str(uint32 ip, char ip_str[16]) { - struct in_addr addr; - addr.s_addr = htonl(ip); - return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); + struct in_addr addr; + addr.s_addr = htonl(ip); + return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); } // Converts a dot-formatted ip string into a numeric ip. -uint32 str2ip(const char* ip_str) +uint32 str2ip(const char *ip_str) { - return ntohl(inet_addr(ip_str)); + return ntohl(inet_addr(ip_str)); } // Reorders bytes from network to little endian (Windows). // Neccessary for sending port numbers to the RO client until Gravity notices that they forgot ntohs() calls. uint16 ntows(uint16 netshort) { - return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); + return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); } #ifdef SEND_SHORTLIST @@ -1382,75 +1364,70 @@ uint16 ntows(uint16 netshort) // sending or eof handling. void send_shortlist_add_fd(int fd) { - int i; - int bit; + int i; + int bit; - if( !session_isValid(fd) ) - return;// out of range + if (!session_isValid(fd)) + return;// out of range - i = fd/32; - bit = fd%32; + i = fd/32; + bit = fd%32; - if( (send_shortlist_set[i]>>bit)&1 ) - return;// already in the list + if ((send_shortlist_set[i]>>bit)&1) + return;// already in the list - if( send_shortlist_count >= ARRAYLENGTH(send_shortlist_array) ) - { - ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); - return; - } + if (send_shortlist_count >= ARRAYLENGTH(send_shortlist_array)) { + ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); + return; + } - // set the bit - send_shortlist_set[i] |= 1<= 0; --i ) - { - int fd = send_shortlist_array[i]; - int idx = fd/32; - int bit = fd%32; - - // Remove fd from shortlist, move the last fd to the current position - --send_shortlist_count; - send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; - send_shortlist_array[send_shortlist_count] = 0; - - if( fd <= 0 || fd >= FD_SETSIZE ) - { - ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); - continue; - } - if( ((send_shortlist_set[idx]>>bit)&1) == 0 ) - { - ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); - continue; - } - send_shortlist_set[idx]&=~(1<wdata_size ) - session[fd]->func_send(fd); - - // If it's been marked as eof, call the parse func on it so that - // the socket will be immediately closed. - if( session[fd]->flag.eof ) - session[fd]->func_parse(fd); - - // If the session still exists, is not eof and has things left to - // be sent from it we'll re-add it to the shortlist. - if( session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size ) - send_shortlist_add_fd(fd); - } - } + int i; + + for (i = send_shortlist_count-1; i >= 0; --i) { + int fd = send_shortlist_array[i]; + int idx = fd/32; + int bit = fd%32; + + // Remove fd from shortlist, move the last fd to the current position + --send_shortlist_count; + send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; + send_shortlist_array[send_shortlist_count] = 0; + + if (fd <= 0 || fd >= FD_SETSIZE) { + ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); + continue; + } + if (((send_shortlist_set[idx]>>bit)&1) == 0) { + ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); + continue; + } + send_shortlist_set[idx]&=~(1<wdata_size) + session[fd]->func_send(fd); + + // If it's been marked as eof, call the parse func on it so that + // the socket will be immediately closed. + if (session[fd]->flag.eof) + session[fd]->func_parse(fd); + + // If the session still exists, is not eof and has things left to + // be sent from it we'll re-add it to the shortlist. + if (session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size) + send_shortlist_add_fd(fd); + } + } } #endif diff --git a/src/common/socket.h b/src/common/socket.h index 7c0e02f5d..5c4008d62 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -1,18 +1,18 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _SOCKET_H_ +#ifndef _SOCKET_H_ #define _SOCKET_H_ #include "../common/cbasetypes.h" #ifdef WIN32 - #include "../common/winapi.h" - typedef long in_addr_t; +#include "../common/winapi.h" +typedef long in_addr_t; #else - #include - #include - #include +#include +#include +#include #endif #include @@ -38,15 +38,15 @@ #define RFIFOREST(fd) (session[fd]->flag.eof ? 0 : session[fd]->rdata_size - session[fd]->rdata_pos) #define RFIFOFLUSH(fd) \ - do { \ - if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ - session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ - } else { \ - session[fd]->rdata_size -= session[fd]->rdata_pos; \ - memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ - session[fd]->rdata_pos = 0; \ - } \ - } while(0) + do { \ + if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ + session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ + } else { \ + session[fd]->rdata_size -= session[fd]->rdata_pos; \ + memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ + session[fd]->rdata_pos = 0; \ + } \ + } while(0) // buffer I/O macros #define RBUFP(p,pos) (((uint8*)(p)) + (pos)) @@ -71,33 +71,32 @@ typedef int (*RecvFunc)(int fd); typedef int (*SendFunc)(int fd); typedef int (*ParseFunc)(int fd); -struct socket_data -{ - struct { - unsigned char eof : 1; - unsigned char server : 1; - unsigned char ping : 2; - } flag; +struct socket_data { + struct { + unsigned char eof : 1; + unsigned char server : 1; + unsigned char ping : 2; + } flag; - uint32 client_addr; // remote client address + uint32 client_addr; // remote client address - uint8 *rdata, *wdata; - size_t max_rdata, max_wdata; - size_t rdata_size, wdata_size; - size_t rdata_pos; - time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled + uint8 *rdata, *wdata; + size_t max_rdata, max_wdata; + size_t rdata_size, wdata_size; + size_t rdata_pos; + time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled - RecvFunc func_recv; - SendFunc func_send; - ParseFunc func_parse; + RecvFunc func_recv; + SendFunc func_send; + ParseFunc func_parse; - void* session_data; // stores application-specific data related to the session + void *session_data; // stores application-specific data related to the session }; // Data prototype declaration -extern struct socket_data* session[FD_SETSIZE]; +extern struct socket_data *session[FD_SETSIZE]; extern int fd_max; @@ -131,21 +130,21 @@ extern void set_nonblocking(int fd, unsigned long yes); void set_defaultparse(ParseFunc defaultparse); // hostname/ip conversion functions -uint32 host2ip(const char* hostname); -const char* ip2str(uint32 ip, char ip_str[16]); -uint32 str2ip(const char* ip_str); +uint32 host2ip(const char *hostname); +const char *ip2str(uint32 ip, char ip_str[16]); +uint32 str2ip(const char *ip_str); #define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF #define MAKEIP(a,b,c,d) (uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) ) uint16 ntows(uint16 netshort); -int socket_getips(uint32* ips, int max); +int socket_getips(uint32 *ips, int max); extern uint32 addr_[16]; // ip addresses of local host (host byte order) extern int naddr_; // # of ip addresses void set_eof(int fd); -/// Use a shortlist of sockets instead of iterating all sessions for sockets +/// Use a shortlist of sockets instead of iterating all sessions for sockets /// that have data to send or need eof handling. /// Adapted to use a static array instead of a linked list. /// diff --git a/src/common/spinlock.h b/src/common/spinlock.h index 3419bfdd5..8d1624b33 100644 --- a/src/common/spinlock.h +++ b/src/common/spinlock.h @@ -14,7 +14,7 @@ // For more information, see LICENCE in the main folder // // - + #ifdef WIN32 #include "../common/winapi.h" #endif @@ -25,77 +25,81 @@ #ifdef WIN32 -typedef struct __declspec( align(64) ) SPIN_LOCK{ - volatile LONG lock; - volatile LONG nest; - volatile LONG sync_lock; +typedef struct __declspec(align(64)) SPIN_LOCK { + volatile LONG lock; + volatile LONG nest; + volatile LONG sync_lock; } SPIN_LOCK, *PSPIN_LOCK; #else -typedef struct SPIN_LOCK{ - volatile int32 lock; - volatile int32 nest; // nesting level. - - volatile int32 sync_lock; +typedef struct SPIN_LOCK { + volatile int32 lock; + volatile int32 nest; // nesting level. + + volatile int32 sync_lock; } __attribute__((aligned(64))) SPIN_LOCK, *PSPIN_LOCK; #endif -static forceinline void InitializeSpinLock(PSPIN_LOCK lck){ - lck->lock = 0; - lck->nest = 0; - lck->sync_lock = 0; +static forceinline void InitializeSpinLock(PSPIN_LOCK lck) +{ + lck->lock = 0; + lck->nest = 0; + lck->sync_lock = 0; } -static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){ - return; +static forceinline void FinalizeSpinLock(PSPIN_LOCK lck) +{ + return; } #define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } } #define dropsynclock(l) { InterlockedExchange(l, 0); } -static forceinline void EnterSpinLock(PSPIN_LOCK lck){ - int tid = rathread_get_tid(); - - // Get Sync Lock && Check if the requester thread already owns the lock. - // if it owns, increase nesting level - getsynclock(&lck->sync_lock); - if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ - InterlockedIncrement(&lck->nest); - dropsynclock(&lck->sync_lock); - return; // Got Lock - } - // drop sync lock - dropsynclock(&lck->sync_lock); - - - // Spin until we've got it ! - while(1){ - - if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){ - - InterlockedIncrement(&lck->nest); - return; // Got Lock - } - - rathread_yield(); // Force ctxswitch to another thread. - } +static forceinline void EnterSpinLock(PSPIN_LOCK lck) +{ + int tid = rathread_get_tid(); + + // Get Sync Lock && Check if the requester thread already owns the lock. + // if it owns, increase nesting level + getsynclock(&lck->sync_lock); + if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { + InterlockedIncrement(&lck->nest); + dropsynclock(&lck->sync_lock); + return; // Got Lock + } + // drop sync lock + dropsynclock(&lck->sync_lock); + + + // Spin until we've got it ! + while (1) { + + if (InterlockedCompareExchange(&lck->lock, tid, 0) == 0) { + + InterlockedIncrement(&lck->nest); + return; // Got Lock + } + + rathread_yield(); // Force ctxswitch to another thread. + } } -static forceinline void LeaveSpinLock(PSPIN_LOCK lck){ - int tid = rathread_get_tid(); +static forceinline void LeaveSpinLock(PSPIN_LOCK lck) +{ + int tid = rathread_get_tid(); + + getsynclock(&lck->sync_lock); + + if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { // this thread owns the lock. + if (InterlockedDecrement(&lck->nest) == 0) + InterlockedExchange(&lck->lock, 0); // Unlock! + } - getsynclock(&lck->sync_lock); - - if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock. - if(InterlockedDecrement(&lck->nest) == 0) - InterlockedExchange(&lck->lock, 0); // Unlock! - } - - dropsynclock(&lck->sync_lock); + dropsynclock(&lck->sync_lock); } diff --git a/src/common/sql.c b/src/common/sql.c index 800aa89b0..740da476d 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -18,41 +18,38 @@ /// Sql handle -struct Sql -{ - StringBuf buf; - MYSQL handle; - MYSQL_RES* result; - MYSQL_ROW row; - unsigned long* lengths; - int keepalive; +struct Sql { + StringBuf buf; + MYSQL handle; + MYSQL_RES *result; + MYSQL_ROW row; + unsigned long *lengths; + int keepalive; }; // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. -struct s_column_length -{ - uint32* out_length; - unsigned long length; +struct s_column_length { + uint32 *out_length; + unsigned long length; }; typedef struct s_column_length s_column_length; /// Sql statement -struct SqlStmt -{ - StringBuf buf; - MYSQL_STMT* stmt; - MYSQL_BIND* params; - MYSQL_BIND* columns; - s_column_length* column_lengths; - size_t max_params; - size_t max_columns; - bool bind_params; - bool bind_columns; +struct SqlStmt { + StringBuf buf; + MYSQL_STMT *stmt; + MYSQL_BIND *params; + MYSQL_BIND *columns; + s_column_length *column_lengths; + size_t max_params; + size_t max_columns; + bool bind_params; + bool bind_columns; }; @@ -64,117 +61,111 @@ struct SqlStmt /// Allocates and initializes a new Sql handle. -Sql* Sql_Malloc(void) +Sql *Sql_Malloc(void) { - Sql* self; + Sql *self; - CREATE(self, Sql, 1); - mysql_init(&self->handle); - StringBuf_Init(&self->buf); - self->lengths = NULL; - self->result = NULL; - self->keepalive = INVALID_TIMER; + CREATE(self, Sql, 1); + mysql_init(&self->handle); + StringBuf_Init(&self->buf); + self->lengths = NULL; + self->result = NULL; + self->keepalive = INVALID_TIMER; - return self; + return self; } -static int Sql_P_Keepalive(Sql* self); +static int Sql_P_Keepalive(Sql *self); /// Establishes a connection. -int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db) +int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - StringBuf_Clear(&self->buf); - if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) - { - ShowSQL("%s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } + StringBuf_Clear(&self->buf); + if (!mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/)) { + ShowSQL("%s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } - self->keepalive = Sql_P_Keepalive(self); - if( self->keepalive == INVALID_TIMER ) - { - ShowSQL("Failed to establish keepalive for DB connection!\n"); - return SQL_ERROR; - } + self->keepalive = Sql_P_Keepalive(self); + if (self->keepalive == INVALID_TIMER) { + ShowSQL("Failed to establish keepalive for DB connection!\n"); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Retrieves the timeout of the connection. -int Sql_GetTimeout(Sql* self, uint32* out_timeout) +int Sql_GetTimeout(Sql *self, uint32 *out_timeout) { - if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) - { - char* data; - size_t len; - if( SQL_SUCCESS == Sql_NextRow(self) && - SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) - { - *out_timeout = (uint32)strtoul(data, NULL, 10); - Sql_FreeResult(self); - return SQL_SUCCESS; - } - Sql_FreeResult(self); - } - return SQL_ERROR; + if (self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'")) { + char *data; + size_t len; + if (SQL_SUCCESS == Sql_NextRow(self) && + SQL_SUCCESS == Sql_GetData(self, 1, &data, &len)) { + *out_timeout = (uint32)strtoul(data, NULL, 10); + Sql_FreeResult(self); + return SQL_SUCCESS; + } + Sql_FreeResult(self); + } + return SQL_ERROR; } /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. -int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep) +int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep) { - char* data; - size_t len; - size_t off = 0; + char *data; + size_t len; + size_t off = 0; - if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) - return SQL_ERROR; + if (self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table)) + return SQL_ERROR; - out_buf[off] = '\0'; - while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) - { - len = strnlen(data, len); - if( off + len + 2 > buf_len ) - { - ShowDebug("Sql_GetColumns: output buffer is too small\n"); - *out_buf = '\0'; - return SQL_ERROR; - } - memcpy(out_buf+off, data, len); - off += len; - out_buf[off++] = sep; - } - out_buf[off] = '\0'; - Sql_FreeResult(self); - return SQL_SUCCESS; + out_buf[off] = '\0'; + while (SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len)) { + len = strnlen(data, len); + if (off + len + 2 > buf_len) { + ShowDebug("Sql_GetColumns: output buffer is too small\n"); + *out_buf = '\0'; + return SQL_ERROR; + } + memcpy(out_buf+off, data, len); + off += len; + out_buf[off++] = sep; + } + out_buf[off] = '\0'; + Sql_FreeResult(self); + return SQL_SUCCESS; } /// Changes the encoding of the connection. -int Sql_SetEncoding(Sql* self, const char* encoding) +int Sql_SetEncoding(Sql *self, const char *encoding) { - if( self && mysql_set_character_set(&self->handle, encoding) == 0 ) - return SQL_SUCCESS; - return SQL_ERROR; + if (self && mysql_set_character_set(&self->handle, encoding) == 0) + return SQL_SUCCESS; + return SQL_ERROR; } /// Pings the connection. -int Sql_Ping(Sql* self) +int Sql_Ping(Sql *self) { - if( self && mysql_ping(&self->handle) == 0 ) - return SQL_SUCCESS; - return SQL_ERROR; + if (self && mysql_ping(&self->handle) == 0) + return SQL_SUCCESS; + return SQL_ERROR; } @@ -184,10 +175,10 @@ int Sql_Ping(Sql* self) /// @private static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data) { - Sql* self = (Sql*)data; - ShowInfo("Pinging SQL server to keep connection alive...\n"); - Sql_Ping(self); - return 0; + Sql *self = (Sql *)data; + ShowInfo("Pinging SQL server to keep connection alive...\n"); + Sql_Ping(self); + return 0; } @@ -196,224 +187,213 @@ static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t dat /// /// @return the keepalive timer id, or INVALID_TIMER /// @private -static int Sql_P_Keepalive(Sql* self) +static int Sql_P_Keepalive(Sql *self) { - uint32 timeout, ping_interval; + uint32 timeout, ping_interval; - // set a default value first - timeout = 28800; // 8 hours + // set a default value first + timeout = 28800; // 8 hours - // request the timeout value from the mysql server - Sql_GetTimeout(self, &timeout); + // request the timeout value from the mysql server + Sql_GetTimeout(self, &timeout); - if( timeout < 60 ) - timeout = 60; + if (timeout < 60) + timeout = 60; - // establish keepalive - ping_interval = timeout - 30; // 30-second reserve - //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); - return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); + // establish keepalive + ping_interval = timeout - 30; // 30-second reserve + //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); + return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } /// Escapes a string. -size_t Sql_EscapeString(Sql* self, char *out_to, const char *from) +size_t Sql_EscapeString(Sql *self, char *out_to, const char *from) { - if( self ) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); + if (self) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); } /// Escapes a string. -size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len) +size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len) { - if( self ) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); + if (self) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); } /// Executes a query. -int Sql_Query(Sql* self, const char* query, ...) +int Sql_Query(Sql *self, const char *query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = Sql_QueryV(self, query, args); - va_end(args); + va_start(args, query); + res = Sql_QueryV(self, query, args); + va_end(args); - return res; + return res; } /// Executes a query. -int Sql_QueryV(Sql* self, const char* query, va_list args) +int Sql_QueryV(Sql *self, const char *query, va_list args) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if( mysql_errno(&self->handle) != 0 ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if (mysql_errno(&self->handle) != 0) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Executes a query. -int Sql_QueryStr(Sql* self, const char* query) +int Sql_QueryStr(Sql *self, const char *query) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if( mysql_errno(&self->handle) != 0 ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if (mysql_errno(&self->handle) != 0) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. -uint64 Sql_LastInsertId(Sql* self) +uint64 Sql_LastInsertId(Sql *self) { - if( self ) - return (uint64)mysql_insert_id(&self->handle); - else - return 0; + if (self) + return (uint64)mysql_insert_id(&self->handle); + else + return 0; } /// Returns the number of columns in each row of the result. -uint32 Sql_NumColumns(Sql* self) +uint32 Sql_NumColumns(Sql *self) { - if( self && self->result ) - return (uint32)mysql_num_fields(self->result); - return 0; + if (self && self->result) + return (uint32)mysql_num_fields(self->result); + return 0; } /// Returns the number of rows in the result. -uint64 Sql_NumRows(Sql* self) +uint64 Sql_NumRows(Sql *self) { - if( self && self->result ) - return (uint64)mysql_num_rows(self->result); - return 0; + if (self && self->result) + return (uint64)mysql_num_rows(self->result); + return 0; } /// Fetches the next row. -int Sql_NextRow(Sql* self) +int Sql_NextRow(Sql *self) { - if( self && self->result ) - { - self->row = mysql_fetch_row(self->result); - if( self->row ) - { - self->lengths = mysql_fetch_lengths(self->result); - return SQL_SUCCESS; - } - self->lengths = NULL; - if( mysql_errno(&self->handle) == 0 ) - return SQL_NO_DATA; - } - return SQL_ERROR; + if (self && self->result) { + self->row = mysql_fetch_row(self->result); + if (self->row) { + self->lengths = mysql_fetch_lengths(self->result); + return SQL_SUCCESS; + } + self->lengths = NULL; + if (mysql_errno(&self->handle) == 0) + return SQL_NO_DATA; + } + return SQL_ERROR; } /// Gets the data of a column. -int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len) +int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len) { - if( self && self->row ) - { - if( col < Sql_NumColumns(self) ) - { - if( out_buf ) *out_buf = self->row[col]; - if( out_len ) *out_len = (size_t)self->lengths[col]; - } - else - {// out of range - ignore - if( out_buf ) *out_buf = NULL; - if( out_len ) *out_len = 0; - } - return SQL_SUCCESS; - } - return SQL_ERROR; + if (self && self->row) { + if (col < Sql_NumColumns(self)) { + if (out_buf) *out_buf = self->row[col]; + if (out_len) *out_len = (size_t)self->lengths[col]; + } else { + // out of range - ignore + if (out_buf) *out_buf = NULL; + if (out_len) *out_len = 0; + } + return SQL_SUCCESS; + } + return SQL_ERROR; } /// Frees the result of the query. -void Sql_FreeResult(Sql* self) +void Sql_FreeResult(Sql *self) { - if( self && self->result ) - { - mysql_free_result(self->result); - self->result = NULL; - self->row = NULL; - self->lengths = NULL; - } + if (self && self->result) { + mysql_free_result(self->result); + self->result = NULL; + self->row = NULL; + self->lengths = NULL; + } } /// Shows debug information (last query). -void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line) +void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line) { - if( self == NULL ) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if (self == NULL) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if (StringBuf_Length(&self->buf) > 0) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql* self) +void Sql_Free(Sql *self) { - if( self ) - { - Sql_FreeResult(self); - StringBuf_Destroy(&self->buf); - if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); - aFree(self); - } + if (self) { + Sql_FreeResult(self); + StringBuf_Destroy(&self->buf); + if (self->keepalive != INVALID_TIMER) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); + aFree(self); + } } @@ -429,16 +409,19 @@ void Sql_Free(Sql* self) /// @private static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) { - switch( sz ) - { - case 1: return MYSQL_TYPE_TINY; - case 2: return MYSQL_TYPE_SHORT; - case 4: return MYSQL_TYPE_LONG; - case 8: return MYSQL_TYPE_LONGLONG; - default: - ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); - return MYSQL_TYPE_NULL; - } + switch (sz) { + case 1: + return MYSQL_TYPE_TINY; + case 2: + return MYSQL_TYPE_SHORT; + case 4: + return MYSQL_TYPE_LONG; + case 8: + return MYSQL_TYPE_LONGLONG; + default: + ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); + return MYSQL_TYPE_NULL; + } } @@ -446,74 +429,96 @@ static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) /// Binds a parameter/result. /// /// @private -static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null) -{ - memset(bind, 0, sizeof(MYSQL_BIND)); - switch( buffer_type ) - { - case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; - buffer_len = 0;// FIXME length = ? [FlavioJS] - break; - // fixed size - case SQLDT_UINT8: bind->is_unsigned = 1; - case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; - buffer_len = 1; - break; - case SQLDT_UINT16: bind->is_unsigned = 1; - case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT; - buffer_len = 2; - break; - case SQLDT_UINT32: bind->is_unsigned = 1; - case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG; - buffer_len = 4; - break; - case SQLDT_UINT64: bind->is_unsigned = 1; - case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; - buffer_len = 8; - break; - // platform dependent size - case SQLDT_UCHAR: bind->is_unsigned = 1; - case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); - buffer_len = sizeof(char); - break; - case SQLDT_USHORT: bind->is_unsigned = 1; - case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); - buffer_len = sizeof(short); - break; - case SQLDT_UINT: bind->is_unsigned = 1; - case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); - buffer_len = sizeof(int); - break; - case SQLDT_ULONG: bind->is_unsigned = 1; - case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); - buffer_len = sizeof(long); - break; - case SQLDT_ULONGLONG: bind->is_unsigned = 1; - case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); - buffer_len = sizeof(int64); - break; - // floating point - case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; - buffer_len = 4; - break; - case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; - buffer_len = 8; - break; - // other - case SQLDT_STRING: - case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; - break; - case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB; - break; - default: - ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); - return SQL_ERROR; - } - bind->buffer = buffer; - bind->buffer_length = (unsigned long)buffer_len; - bind->length = out_length; - bind->is_null = (my_bool*)out_is_null; - return SQL_SUCCESS; +static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, unsigned long *out_length, int8 *out_is_null) +{ + memset(bind, 0, sizeof(MYSQL_BIND)); + switch (buffer_type) { + case SQLDT_NULL: + bind->buffer_type = MYSQL_TYPE_NULL; + buffer_len = 0;// FIXME length = ? [FlavioJS] + break; + // fixed size + case SQLDT_UINT8: + bind->is_unsigned = 1; + case SQLDT_INT8: + bind->buffer_type = MYSQL_TYPE_TINY; + buffer_len = 1; + break; + case SQLDT_UINT16: + bind->is_unsigned = 1; + case SQLDT_INT16: + bind->buffer_type = MYSQL_TYPE_SHORT; + buffer_len = 2; + break; + case SQLDT_UINT32: + bind->is_unsigned = 1; + case SQLDT_INT32: + bind->buffer_type = MYSQL_TYPE_LONG; + buffer_len = 4; + break; + case SQLDT_UINT64: + bind->is_unsigned = 1; + case SQLDT_INT64: + bind->buffer_type = MYSQL_TYPE_LONGLONG; + buffer_len = 8; + break; + // platform dependent size + case SQLDT_UCHAR: + bind->is_unsigned = 1; + case SQLDT_CHAR: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); + buffer_len = sizeof(char); + break; + case SQLDT_USHORT: + bind->is_unsigned = 1; + case SQLDT_SHORT: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); + buffer_len = sizeof(short); + break; + case SQLDT_UINT: + bind->is_unsigned = 1; + case SQLDT_INT: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); + buffer_len = sizeof(int); + break; + case SQLDT_ULONG: + bind->is_unsigned = 1; + case SQLDT_LONG: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); + buffer_len = sizeof(long); + break; + case SQLDT_ULONGLONG: + bind->is_unsigned = 1; + case SQLDT_LONGLONG: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); + buffer_len = sizeof(int64); + break; + // floating point + case SQLDT_FLOAT: + bind->buffer_type = MYSQL_TYPE_FLOAT; + buffer_len = 4; + break; + case SQLDT_DOUBLE: + bind->buffer_type = MYSQL_TYPE_DOUBLE; + buffer_len = 8; + break; + // other + case SQLDT_STRING: + case SQLDT_ENUM: + bind->buffer_type = MYSQL_TYPE_STRING; + break; + case SQLDT_BLOB: + bind->buffer_type = MYSQL_TYPE_BLOB; + break; + default: + ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); + return SQL_ERROR; + } + bind->buffer = buffer; + bind->buffer_length = (unsigned long)buffer_len; + bind->length = out_length; + bind->is_null = (my_bool *)out_is_null; + return SQL_SUCCESS; } @@ -521,38 +526,37 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, /// Prints debug information about a field (type and length). /// /// @private -static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) -{ - const char* sign = (is_unsigned ? "UNSIGNED " : ""); - const char* type_string; - switch( type ) - { - default: - ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); - return; +static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char *length_postfix) +{ + const char *sign = (is_unsigned ? "UNSIGNED " : ""); + const char *type_string; + switch (type) { + default: + ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); + return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break - SHOW_DEBUG_OF(MYSQL_TYPE_TINY); - SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); - SHOW_DEBUG_OF(MYSQL_TYPE_LONG); - SHOW_DEBUG_OF(MYSQL_TYPE_INT24); - SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); - SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); - SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); - SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); - SHOW_DEBUG_OF(MYSQL_TYPE_DATE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIME); - SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); - SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); - SHOW_DEBUG_OF(MYSQL_TYPE_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); - SHOW_DEBUG_OF(MYSQL_TYPE_SET); - SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); - SHOW_DEBUG_OF(MYSQL_TYPE_NULL); + SHOW_DEBUG_OF(MYSQL_TYPE_TINY); + SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); + SHOW_DEBUG_OF(MYSQL_TYPE_LONG); + SHOW_DEBUG_OF(MYSQL_TYPE_INT24); + SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); + SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); + SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); + SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); + SHOW_DEBUG_OF(MYSQL_TYPE_DATE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIME); + SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); + SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); + SHOW_DEBUG_OF(MYSQL_TYPE_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); + SHOW_DEBUG_OF(MYSQL_TYPE_SET); + SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); + SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF - } - ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); + } + ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); } @@ -560,389 +564,369 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_ty /// Reports debug information about a truncated column. /// /// @private -static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) +static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt *self, size_t i) { - MYSQL_RES* meta; - MYSQL_FIELD* field; - MYSQL_BIND* column; + MYSQL_RES *meta; + MYSQL_FIELD *field; + MYSQL_BIND *column; - meta = mysql_stmt_result_metadata(self->stmt); - field = mysql_fetch_field_direct(meta, (unsigned int)i); - ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); - ShowDebug("column - %lu\n", (unsigned long)i); - Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); - column = &self->columns[i]; - if( column->buffer_type == MYSQL_TYPE_STRING ) - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); - else - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); - mysql_free_result(meta); + meta = mysql_stmt_result_metadata(self->stmt); + field = mysql_fetch_field_direct(meta, (unsigned int)i); + ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); + ShowDebug("column - %lu\n", (unsigned long)i); + Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); + column = &self->columns[i]; + if (column->buffer_type == MYSQL_TYPE_STRING) + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); + else + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); + mysql_free_result(meta); } /// Allocates and initializes a new SqlStmt handle. -SqlStmt* SqlStmt_Malloc(Sql* sql) +SqlStmt *SqlStmt_Malloc(Sql *sql) { - SqlStmt* self; - MYSQL_STMT* stmt; + SqlStmt *self; + MYSQL_STMT *stmt; - if( sql == NULL ) - return NULL; + if (sql == NULL) + return NULL; - stmt = mysql_stmt_init(&sql->handle); - if( stmt == NULL ) - { - ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); - return NULL; - } - CREATE(self, SqlStmt, 1); - StringBuf_Init(&self->buf); - self->stmt = stmt; - self->params = NULL; - self->columns = NULL; - self->column_lengths = NULL; - self->max_params = 0; - self->max_columns = 0; - self->bind_params = false; - self->bind_columns = false; + stmt = mysql_stmt_init(&sql->handle); + if (stmt == NULL) { + ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); + return NULL; + } + CREATE(self, SqlStmt, 1); + StringBuf_Init(&self->buf); + self->stmt = stmt; + self->params = NULL; + self->columns = NULL; + self->column_lengths = NULL; + self->max_params = 0; + self->max_columns = 0; + self->bind_params = false; + self->bind_columns = false; - return self; + return self; } /// Prepares the statement. -int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) +int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = SqlStmt_PrepareV(self, query, args); - va_end(args); + va_start(args, query); + res = SqlStmt_PrepareV(self, query, args); + va_end(args); - return res; + return res; } /// Prepares the statement. -int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) +int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Prepares the statement. -int SqlStmt_PrepareStr(SqlStmt* self, const char* query) +int SqlStmt_PrepareStr(SqlStmt *self, const char *query) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of parameters in the prepared statement. -size_t SqlStmt_NumParams(SqlStmt* self) +size_t SqlStmt_NumParams(SqlStmt *self) { - if( self ) - return (size_t)mysql_stmt_param_count(self->stmt); - else - return 0; + if (self) + return (size_t)mysql_stmt_param_count(self->stmt); + else + return 0; } /// Binds a parameter to a buffer. -int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) +int SqlStmt_BindParam(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - if( !self->bind_params ) - {// initialize the bindings - size_t i; - size_t count; + if (!self->bind_params) { + // initialize the bindings + size_t i; + size_t count; - count = SqlStmt_NumParams(self); - if( self->max_params < count ) - { - self->max_params = count; - RECREATE(self->params, MYSQL_BIND, count); - } - memset(self->params, 0, count*sizeof(MYSQL_BIND)); - for( i = 0; i < count; ++i ) - self->params[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_params = true; - } - if( idx < self->max_params ) - return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); - else - return SQL_SUCCESS;// out of range - ignore + count = SqlStmt_NumParams(self); + if (self->max_params < count) { + self->max_params = count; + RECREATE(self->params, MYSQL_BIND, count); + } + memset(self->params, 0, count*sizeof(MYSQL_BIND)); + for (i = 0; i < count; ++i) + self->params[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_params = true; + } + if (idx < self->max_params) + return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); + else + return SQL_SUCCESS;// out of range - ignore } /// Executes the prepared statement. -int SqlStmt_Execute(SqlStmt* self) +int SqlStmt_Execute(SqlStmt *self) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || - mysql_stmt_execute(self->stmt) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_columns = false; - if( mysql_stmt_store_result(self->stmt) )// store all the data - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } + SqlStmt_FreeResult(self); + if ((self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || + mysql_stmt_execute(self->stmt)) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_columns = false; + if (mysql_stmt_store_result(self->stmt)) { // store all the data + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. -uint64 SqlStmt_LastInsertId(SqlStmt* self) +uint64 SqlStmt_LastInsertId(SqlStmt *self) { - if( self ) - return (uint64)mysql_stmt_insert_id(self->stmt); - else - return 0; + if (self) + return (uint64)mysql_stmt_insert_id(self->stmt); + else + return 0; } /// Returns the number of columns in each row of the result. -size_t SqlStmt_NumColumns(SqlStmt* self) +size_t SqlStmt_NumColumns(SqlStmt *self) { - if( self ) - return (size_t)mysql_stmt_field_count(self->stmt); - else - return 0; + if (self) + return (size_t)mysql_stmt_field_count(self->stmt); + else + return 0; } /// Binds the result of a column to a buffer. -int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null) -{ - if( self == NULL ) - return SQL_ERROR; - - if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM ) - { - if( buffer_len < 1 ) - { - ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); - return SQL_ERROR; - } - --buffer_len;// nul-terminator - } - if( !self->bind_columns ) - {// initialize the bindings - size_t i; - size_t cols; - - cols = SqlStmt_NumColumns(self); - if( self->max_columns < cols ) - { - self->max_columns = cols; - RECREATE(self->columns, MYSQL_BIND, cols); - RECREATE(self->column_lengths, s_column_length, cols); - } - memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); - memset(self->column_lengths, 0, cols*sizeof(s_column_length)); - for( i = 0; i < cols; ++i ) - self->columns[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_columns = true; - } - if( idx < self->max_columns ) - { - self->column_lengths[idx].out_length = out_length; - return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); - } - else - { - return SQL_SUCCESS;// out of range - ignore - } +int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null) +{ + if (self == NULL) + return SQL_ERROR; + + if (buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM) { + if (buffer_len < 1) { + ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); + return SQL_ERROR; + } + --buffer_len;// nul-terminator + } + if (!self->bind_columns) { + // initialize the bindings + size_t i; + size_t cols; + + cols = SqlStmt_NumColumns(self); + if (self->max_columns < cols) { + self->max_columns = cols; + RECREATE(self->columns, MYSQL_BIND, cols); + RECREATE(self->column_lengths, s_column_length, cols); + } + memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); + memset(self->column_lengths, 0, cols*sizeof(s_column_length)); + for (i = 0; i < cols; ++i) + self->columns[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_columns = true; + } + if (idx < self->max_columns) { + self->column_lengths[idx].out_length = out_length; + return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); + } else { + return SQL_SUCCESS;// out of range - ignore + } } /// Returns the number of rows in the result. -uint64 SqlStmt_NumRows(SqlStmt* self) +uint64 SqlStmt_NumRows(SqlStmt *self) { - if( self ) - return (uint64)mysql_stmt_num_rows(self->stmt); - else - return 0; + if (self) + return (uint64)mysql_stmt_num_rows(self->stmt); + else + return 0; } /// Fetches the next row. -int SqlStmt_NextRow(SqlStmt* self) -{ - int err; - size_t i; - size_t cols; - MYSQL_BIND* column; - unsigned long length; - - if( self == NULL ) - return SQL_ERROR; - - // bind columns - if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) ) - err = 1;// error binding columns - else - err = mysql_stmt_fetch(self->stmt);// fetch row - - // check for errors - if( err == MYSQL_NO_DATA ) - return SQL_NO_DATA; +int SqlStmt_NextRow(SqlStmt *self) +{ + int err; + size_t i; + size_t cols; + MYSQL_BIND *column; + unsigned long length; + + if (self == NULL) + return SQL_ERROR; + + // bind columns + if (self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns)) + err = 1;// error binding columns + else + err = mysql_stmt_fetch(self->stmt);// fetch row + + // check for errors + if (err == MYSQL_NO_DATA) + return SQL_NO_DATA; #if defined(MYSQL_DATA_TRUNCATED) - // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] - if( err == MYSQL_DATA_TRUNCATED ) - { - my_bool truncated; - - if( !self->bind_columns ) - { - ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); - return SQL_ERROR; - } - - // find truncated column - cols = SqlStmt_NumColumns(self); - for( i = 0; i < cols; ++i ) - { - column = &self->columns[i]; - column->error = &truncated; - mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); - column->error = NULL; - if( truncated ) - {// report truncated column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - } - ShowSQL("DB error - data truncated (unknown source)\n"); - return SQL_ERROR; - } + // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] + if (err == MYSQL_DATA_TRUNCATED) { + my_bool truncated; + + if (!self->bind_columns) { + ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); + return SQL_ERROR; + } + + // find truncated column + cols = SqlStmt_NumColumns(self); + for (i = 0; i < cols; ++i) { + column = &self->columns[i]; + column->error = &truncated; + mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); + column->error = NULL; + if (truncated) { + // report truncated column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + } + ShowSQL("DB error - data truncated (unknown source)\n"); + return SQL_ERROR; + } #endif - if( err ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - - // propagate column lengths and clear unused parts of string/enum/blob buffers - cols = SqlStmt_NumColumns(self); - for( i = 0; i < cols; ++i ) - { - length = self->column_lengths[i].length; - column = &self->columns[i]; + if (err) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + + // propagate column lengths and clear unused parts of string/enum/blob buffers + cols = SqlStmt_NumColumns(self); + for (i = 0; i < cols; ++i) { + length = self->column_lengths[i].length; + column = &self->columns[i]; #if !defined(MYSQL_DATA_TRUNCATED) - // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] - if( column->buffer_length < length ) - {// report truncated column - if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB ) - {// string/enum/blob column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - // FIXME numeric types and null [FlavioJS] - } + // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] + if (column->buffer_length < length) { + // report truncated column + if (column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB) { + // string/enum/blob column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + // FIXME numeric types and null [FlavioJS] + } #endif - if( self->column_lengths[i].out_length ) - *self->column_lengths[i].out_length = (uint32)length; - if( column->buffer_type == MYSQL_TYPE_STRING ) - {// clear unused part of the string/enum buffer (and nul-terminate) - memset((char*)column->buffer + length, 0, column->buffer_length - length + 1); - } - else if( column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length ) - {// clear unused part of the blob buffer - memset((char*)column->buffer + length, 0, column->buffer_length - length); - } - } + if (self->column_lengths[i].out_length) + *self->column_lengths[i].out_length = (uint32)length; + if (column->buffer_type == MYSQL_TYPE_STRING) { + // clear unused part of the string/enum buffer (and nul-terminate) + memset((char *)column->buffer + length, 0, column->buffer_length - length + 1); + } else if (column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length) { + // clear unused part of the blob buffer + memset((char *)column->buffer + length, 0, column->buffer_length - length); + } + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt* self) +void SqlStmt_FreeResult(SqlStmt *self) { - if( self ) - mysql_stmt_free_result(self->stmt); + if (self) + mysql_stmt_free_result(self->stmt); } /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line) +void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line) { - if( self == NULL ) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if (self == NULL) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if (StringBuf_Length(&self->buf) > 0) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt* self) -{ - if( self ) - { - SqlStmt_FreeResult(self); - StringBuf_Destroy(&self->buf); - mysql_stmt_close(self->stmt); - if( self->params ) - aFree(self->params); - if( self->columns ) - { - aFree(self->columns); - aFree(self->column_lengths); - } - aFree(self); - } +void SqlStmt_Free(SqlStmt *self) +{ + if (self) { + SqlStmt_FreeResult(self); + StringBuf_Destroy(&self->buf); + mysql_stmt_close(self->stmt); + if (self->params) + aFree(self->params); + if (self->columns) { + aFree(self->columns); + aFree(self->column_lengths); + } + aFree(self); + } } diff --git a/src/common/sql.h b/src/common/sql.h index 898e2c778..4534061e0 100644 --- a/src/common/sql.h +++ b/src/common/sql.h @@ -21,39 +21,38 @@ /// Data type identifier. /// String, enum and blob data types need the buffer length specified. -enum SqlDataType -{ - SQLDT_NULL, - // fixed size - SQLDT_INT8, - SQLDT_INT16, - SQLDT_INT32, - SQLDT_INT64, - SQLDT_UINT8, - SQLDT_UINT16, - SQLDT_UINT32, - SQLDT_UINT64, - // platform dependent size - SQLDT_CHAR, - SQLDT_SHORT, - SQLDT_INT, - SQLDT_LONG, - SQLDT_LONGLONG, - SQLDT_UCHAR, - SQLDT_USHORT, - SQLDT_UINT, - SQLDT_ULONG, - SQLDT_ULONGLONG, - // floating point - SQLDT_FLOAT, - SQLDT_DOUBLE, - // other - SQLDT_STRING, - SQLDT_ENUM, - // Note: An ENUM is a string with restricted values. When an invalid value - // is inserted, it is saved as an empty string (numerical value 0). - SQLDT_BLOB, - SQLDT_LASTID +enum SqlDataType { + SQLDT_NULL, + // fixed size + SQLDT_INT8, + SQLDT_INT16, + SQLDT_INT32, + SQLDT_INT64, + SQLDT_UINT8, + SQLDT_UINT16, + SQLDT_UINT32, + SQLDT_UINT64, + // platform dependent size + SQLDT_CHAR, + SQLDT_SHORT, + SQLDT_INT, + SQLDT_LONG, + SQLDT_LONGLONG, + SQLDT_UCHAR, + SQLDT_USHORT, + SQLDT_UINT, + SQLDT_ULONG, + SQLDT_ULONGLONG, + // floating point + SQLDT_FLOAT, + SQLDT_DOUBLE, + // other + SQLDT_STRING, + SQLDT_ENUM, + // Note: An ENUM is a string with restricted values. When an invalid value + // is inserted, it is saved as an empty string (numerical value 0). + SQLDT_BLOB, + SQLDT_LASTID }; struct Sql;// Sql handle (private access) @@ -65,14 +64,14 @@ typedef struct SqlStmt SqlStmt; /// Allocates and initializes a new Sql handle. -struct Sql* Sql_Malloc(void); +struct Sql *Sql_Malloc(void); /// Establishes a connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db); +int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db); @@ -80,7 +79,7 @@ int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* hos /// Retrieves the timeout of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetTimeout(Sql* self, uint32* out_timeout); +int Sql_GetTimeout(Sql *self, uint32 *out_timeout); @@ -88,7 +87,7 @@ int Sql_GetTimeout(Sql* self, uint32* out_timeout); /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep); +int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep); @@ -96,14 +95,14 @@ int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_l /// Changes the encoding of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_SetEncoding(Sql* self, const char* encoding); +int Sql_SetEncoding(Sql *self, const char *encoding); /// Pings the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Ping(Sql* self); +int Sql_Ping(Sql *self); @@ -111,7 +110,7 @@ int Sql_Ping(Sql* self); /// The output buffer must be at least strlen(from)*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeString(Sql* self, char* out_to, const char* from); +size_t Sql_EscapeString(Sql *self, char *out_to, const char *from); @@ -119,7 +118,7 @@ size_t Sql_EscapeString(Sql* self, char* out_to, const char* from); /// The output buffer must be at least from_len*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeStringLen(Sql* self, char* out_to, const char* from, size_t from_len); +size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len); @@ -128,7 +127,7 @@ size_t Sql_EscapeStringLen(Sql* self, char* out_to, const char* from, size_t fro /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Query(Sql* self, const char* query, ...); +int Sql_Query(Sql *self, const char *query, ...); @@ -137,7 +136,7 @@ int Sql_Query(Sql* self, const char* query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryV(Sql* self, const char* query, va_list args); +int Sql_QueryV(Sql *self, const char *query, va_list args); @@ -146,28 +145,28 @@ int Sql_QueryV(Sql* self, const char* query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryStr(Sql* self, const char* query); +int Sql_QueryStr(Sql *self, const char *query); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. /// /// @return Value of the auto-increment column -uint64 Sql_LastInsertId(Sql* self); +uint64 Sql_LastInsertId(Sql *self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -uint32 Sql_NumColumns(Sql* self); +uint32 Sql_NumColumns(Sql *self); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 Sql_NumRows(Sql* self); +uint64 Sql_NumRows(Sql *self); @@ -175,7 +174,7 @@ uint64 Sql_NumRows(Sql* self); /// The data of the previous row is no longer valid. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int Sql_NextRow(Sql* self); +int Sql_NextRow(Sql *self); @@ -183,12 +182,12 @@ int Sql_NextRow(Sql* self); /// The data remains valid until the next row is fetched or the result is freed. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len); +int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len); /// Frees the result of the query. -void Sql_FreeResult(Sql* self); +void Sql_FreeResult(Sql *self); @@ -198,22 +197,22 @@ void Sql_FreeResult(Sql* self); #define Sql_ShowDebug(self) Sql_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (last query). -void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line); +void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line); /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql* self); +void Sql_Free(Sql *self); /////////////////////////////////////////////////////////////////////////////// // Prepared Statements /////////////////////////////////////////////////////////////////////////////// -// Parameters are placed in the statement by embedding question mark ('?') +// Parameters are placed in the statement by embedding question mark ('?') // characters into the query at the appropriate positions. // The markers are legal only in places where they represent data. -// The markers cannot be inside quotes. Quotes will be added automatically +// The markers cannot be inside quotes. Quotes will be added automatically // when they are required. // // example queries with parameters: @@ -227,7 +226,7 @@ void Sql_Free(Sql* self); /// Queries in Sql and SqlStmt are independent and don't affect each other. /// /// @return SqlStmt handle or NULL if an error occured -struct SqlStmt* SqlStmt_Malloc(Sql* sql); +struct SqlStmt *SqlStmt_Malloc(Sql *sql); @@ -236,7 +235,7 @@ struct SqlStmt* SqlStmt_Malloc(Sql* sql); /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); +int SqlStmt_Prepare(SqlStmt *self, const char *query, ...); @@ -245,7 +244,7 @@ int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); +int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args); @@ -254,14 +253,14 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareStr(SqlStmt* self, const char* query); +int SqlStmt_PrepareStr(SqlStmt *self, const char *query); /// Returns the number of parameters in the prepared statement. /// /// @return Number or paramenters -size_t SqlStmt_NumParams(SqlStmt* self); +size_t SqlStmt_NumParams(SqlStmt *self); @@ -270,7 +269,7 @@ size_t SqlStmt_NumParams(SqlStmt* self); /// All parameters should have bindings. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len); +int SqlStmt_BindParam(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len); @@ -278,38 +277,38 @@ int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* /// Any previous result is freed and all column bindings are removed. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Execute(SqlStmt* self); +int SqlStmt_Execute(SqlStmt *self); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. /// /// @return Value of the auto-increment column -uint64 SqlStmt_LastInsertId(SqlStmt* self); +uint64 SqlStmt_LastInsertId(SqlStmt *self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -size_t SqlStmt_NumColumns(SqlStmt* self); +size_t SqlStmt_NumColumns(SqlStmt *self); /// Binds the result of a column to a buffer. /// The buffer will be filled with data when the next row is fetched. -/// For string/enum buffer types there has to be enough space for the data +/// For string/enum buffer types there has to be enough space for the data /// and the nul-terminator (an extra byte). /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindColumn(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null); +int SqlStmt_BindColumn(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 SqlStmt_NumRows(SqlStmt* self); +uint64 SqlStmt_NumRows(SqlStmt *self); @@ -317,12 +316,12 @@ uint64 SqlStmt_NumRows(SqlStmt* self); /// All column bindings will be filled with data. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int SqlStmt_NextRow(SqlStmt* self); +int SqlStmt_NextRow(SqlStmt *self); /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt* self); +void SqlStmt_FreeResult(SqlStmt *self); @@ -332,12 +331,12 @@ void SqlStmt_FreeResult(SqlStmt* self); #define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line); +void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line); /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt* self); +void SqlStmt_Free(SqlStmt *self); diff --git a/src/common/strlib.c b/src/common/strlib.c index dfacbf136..89aac3b40 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -14,360 +14,348 @@ #define J_MAX_MALLOC_SIZE 65535 // escapes a string in-place (' -> \' , \ -> \\ , % -> _) -char* jstrescape (char* pt) +char *jstrescape(char *pt) { - //copy from here - char *ptr; - int i = 0, j = 0; - - //copy string to temporary - CREATE(ptr, char, J_MAX_MALLOC_SIZE); - strcpy(ptr,pt); - - while (ptr[i] != '\0') { - switch (ptr[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = ptr[i++]; - } - } - pt[j++] = '\0'; - aFree(ptr); - return pt; + //copy from here + char *ptr; + int i = 0, j = 0; + + //copy string to temporary + CREATE(ptr, char, J_MAX_MALLOC_SIZE); + strcpy(ptr,pt); + + while (ptr[i] != '\0') { + switch (ptr[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = ptr[i++]; + } + } + pt[j++] = '\0'; + aFree(ptr); + return pt; } // escapes a string into a provided buffer -char* jstrescapecpy (char* pt, const char* spt) +char *jstrescapecpy(char *pt, const char *spt) { - //copy from here - //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time - //a escape character is found, the target's final length increases! [Skotlex] - int i =0, j=0; - - if (!spt) { //Return an empty string [Skotlex] - pt[0] = '\0'; - return &pt[0]; - } - - while (spt[i] != '\0') { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - pt[j++] = '\0'; - return &pt[0]; + //copy from here + //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time + //a escape character is found, the target's final length increases! [Skotlex] + int i =0, j=0; + + if (!spt) { //Return an empty string [Skotlex] + pt[0] = '\0'; + return &pt[0]; + } + + while (spt[i] != '\0') { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + pt[j++] = '\0'; + return &pt[0]; } // escapes exactly 'size' bytes of a string into a provided buffer -int jmemescapecpy (char* pt, const char* spt, int size) +int jmemescapecpy(char *pt, const char *spt, int size) { - //copy from here - int i =0, j=0; - - while (i < size) { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - // copy size is 0 ~ (j-1) - return j; + //copy from here + int i =0, j=0; + + while (i < size) { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + // copy size is 0 ~ (j-1) + return j; } // Function to suppress control characters in a string. -int remove_control_chars(char* str) +int remove_control_chars(char *str) { - int i; - int change = 0; + int i; + int change = 0; - for(i = 0; str[i]; i++) { - if (ISCNTRL(str[i])) { - str[i] = '_'; - change = 1; - } - } + for (i = 0; str[i]; i++) { + if (ISCNTRL(str[i])) { + str[i] = '_'; + change = 1; + } + } - return change; + return change; } // Removes characters identified by ISSPACE from the start and end of the string // NOTE: make sure the string is not const!! -char* trim(char* str) +char *trim(char *str) { - size_t start; - size_t end; - - if( str == NULL ) - return str; - - // get start position - for( start = 0; str[start] && ISSPACE(str[start]); ++start ) - ; - // get end position - for( end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end ) - ; - // trim - if( start == end ) - *str = '\0';// empty string - else - {// move string with nul terminator - str[end] = '\0'; - memmove(str,str+start,end-start+1); - } - return str; + size_t start; + size_t end; + + if (str == NULL) + return str; + + // get start position + for (start = 0; str[start] && ISSPACE(str[start]); ++start) + ; + // get end position + for (end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end) + ; + // trim + if (start == end) + *str = '\0';// empty string + else { + // move string with nul terminator + str[end] = '\0'; + memmove(str,str+start,end-start+1); + } + return str; } // Converts one or more consecutive occurences of the delimiters into a single space // and removes such occurences from the beginning and end of string // NOTE: make sure the string is not const!! -char* normalize_name(char* str,const char* delims) +char *normalize_name(char *str,const char *delims) { - char* in = str; - char* out = str; - int put_space = 0; - - if( str == NULL || delims == NULL ) - return str; - - // trim start of string - while( *in && strchr(delims,*in) ) - ++in; - while( *in ) - { - if( put_space ) - {// replace trim characters with a single space - *out = ' '; - ++out; - } - // copy non trim characters - while( *in && !strchr(delims,*in) ) - { - *out = *in; - ++out; - ++in; - } - // skip trim characters - while( *in && strchr(delims,*in) ) - ++in; - put_space = 1; - } - *out = '\0'; - return str; + char *in = str; + char *out = str; + int put_space = 0; + + if (str == NULL || delims == NULL) + return str; + + // trim start of string + while (*in && strchr(delims,*in)) + ++in; + while (*in) { + if (put_space) { + // replace trim characters with a single space + *out = ' '; + ++out; + } + // copy non trim characters + while (*in && !strchr(delims,*in)) { + *out = *in; + ++out; + ++in; + } + // skip trim characters + while (*in && strchr(delims,*in)) + ++in; + put_space = 1; + } + *out = '\0'; + return str; } -//stristr: Case insensitive version of strstr, code taken from +//stristr: Case insensitive version of strstr, code taken from //http://www.daniweb.com/code/snippet313.html, Dave Sinkula // -const char* stristr(const char* haystack, const char* needle) +const char *stristr(const char *haystack, const char *needle) { - if ( !*needle ) - { - return haystack; - } - for ( ; *haystack; ++haystack ) - { - if ( TOUPPER(*haystack) == TOUPPER(*needle) ) - { - // matched starting char -- loop through remaining chars - const char *h, *n; - for ( h = haystack, n = needle; *h && *n; ++h, ++n ) - { - if ( TOUPPER(*h) != TOUPPER(*n) ) - { - break; - } - } - if ( !*n ) // matched all of 'needle' to null termination - { - return haystack; // return the start of the match - } - } - } - return 0; + if (!*needle) { + return haystack; + } + for (; *haystack; ++haystack) { + if (TOUPPER(*haystack) == TOUPPER(*needle)) { + // matched starting char -- loop through remaining chars + const char *h, *n; + for (h = haystack, n = needle; *h && *n; ++h, ++n) { + if (TOUPPER(*h) != TOUPPER(*n)) { + break; + } + } + if (!*n) { // matched all of 'needle' to null termination + return haystack; // return the start of the match + } + } + } + return 0; } #ifdef __WIN32 -char* _strtok_r(char *s1, const char *s2, char **lasts) +char *_strtok_r(char *s1, const char *s2, char **lasts) { - char *ret; - - if (s1 == NULL) - s1 = *lasts; - while(*s1 && strchr(s2, *s1)) - ++s1; - if(*s1 == '\0') - return NULL; - ret = s1; - while(*s1 && !strchr(s2, *s1)) - ++s1; - if(*s1) - *s1++ = '\0'; - *lasts = s1; - return ret; + char *ret; + + if (s1 == NULL) + s1 = *lasts; + while (*s1 && strchr(s2, *s1)) + ++s1; + if (*s1 == '\0') + return NULL; + ret = s1; + while (*s1 && !strchr(s2, *s1)) + ++s1; + if (*s1) + *s1++ = '\0'; + *lasts = s1; + return ret; } #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ -size_t strnlen (const char* string, size_t maxlen) +size_t strnlen(const char *string, size_t maxlen) { - const char* end = (const char*)memchr(string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; + const char *end = (const char *)memchr(string, '\0', maxlen); + return end ? (size_t)(end - string) : maxlen; } #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base) +uint64 strtoull(const char *str, char **endptr, int base) { - uint64 result; - int count; - int n; - - if( base == 0 ) - { - if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) - base = 16; - else - if( str[0] == '0' ) - base = 8; - else - base = 10; - } - - if( base == 8 ) - count = sscanf(str, "%I64o%n", &result, &n); - else - if( base == 10 ) - count = sscanf(str, "%I64u%n", &result, &n); - else - if( base == 16 ) - count = sscanf(str, "%I64x%n", &result, &n); - else - count = 0; // fail - - if( count < 1 ) - { - errno = EINVAL; - result = 0; - n = 0; - } - - if( endptr ) - *endptr = (char*)str + n; - - return result; + uint64 result; + int count; + int n; + + if (base == 0) { + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + base = 16; + else if (str[0] == '0') + base = 8; + else + base = 10; + } + + if (base == 8) + count = sscanf(str, "%I64o%n", &result, &n); + else if (base == 10) + count = sscanf(str, "%I64u%n", &result, &n); + else if (base == 16) + count = sscanf(str, "%I64x%n", &result, &n); + else + count = 0; // fail + + if (count < 1) { + errno = EINVAL; + result = 0; + n = 0; + } + + if (endptr) + *endptr = (char *)str + n; + + return result; } #endif //---------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //---------------------------------------------------- -int e_mail_check(char* email) +int e_mail_check(char *email) { - char ch; - char* last_arobas; - size_t len = strlen(email); + char ch; + char *last_arobas; + size_t len = strlen(email); - // athena limits - if (len < 3 || len > 39) - return 0; + // athena limits + if (len < 3 || len > 39) + return 0; - // part of RFC limits (official reference of e-mail description) - if (strchr(email, '@') == NULL || email[len-1] == '@') - return 0; + // part of RFC limits (official reference of e-mail description) + if (strchr(email, '@') == NULL || email[len-1] == '@') + return 0; - if (email[len-1] == '.') - return 0; + if (email[len-1] == '.') + return 0; - last_arobas = strrchr(email, '@'); + last_arobas = strrchr(email, '@'); - if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) - return 0; + if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) + return 0; - for(ch = 1; ch < 32; ch++) - if (strchr(last_arobas, ch) != NULL) - return 0; + for (ch = 1; ch < 32; ch++) + if (strchr(last_arobas, ch) != NULL) + return 0; - if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) - return 0; + if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) + return 0; - // all correct - return 1; + // all correct + return 1; } //-------------------------------------------------- // Return numerical value of a switch configuration // on/off, english, fran軋is, deutsch, espaol //-------------------------------------------------- -int config_switch(const char* str) +int config_switch(const char *str) { - if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) - return 1; - if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) - return 0; + if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) + return 1; + if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) + return 0; - return (int)strtol(str, NULL, 0); + return (int)strtol(str, NULL, 0); } /// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n) +char *safestrncpy(char *dst, const char *src, size_t n) { - if( n > 0 ) - { - char* d = dst; - const char* s = src; - d[--n] = '\0';/* nul-terminate string */ - for( ; n > 0; --n ) - { - if( (*d++ = *s++) == '\0' ) - {/* nul-pad remaining bytes */ - while( --n > 0 ) - *d++ = '\0'; - break; - } - } - } - return dst; + if (n > 0) { + char *d = dst; + const char *s = src; + d[--n] = '\0';/* nul-terminate string */ + for (; n > 0; --n) { + if ((*d++ = *s++) == '\0') { + /* nul-pad remaining bytes */ + while (--n > 0) + *d++ = '\0'; + break; + } + } + } + return dst; } /// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen) +size_t safestrnlen(const char *string, size_t maxlen) { - return ( string != NULL ) ? strnlen(string, maxlen) : 0; + return (string != NULL) ? strnlen(string, maxlen) : 0; } /// Works like snprintf, but always nul-terminates the buffer. @@ -379,41 +367,40 @@ size_t safestrnlen(const char* string, size_t maxlen) /// @param fmt Format string /// @param ... Format arguments /// @return The size of the string or -1 if the buffer is too small -int safesnprintf(char* buf, size_t sz, const char* fmt, ...) +int safesnprintf(char *buf, size_t sz, const char *fmt, ...) { - va_list ap; - int ret; - - va_start(ap,fmt); - ret = vsnprintf(buf, sz, fmt, ap); - va_end(ap); - if( ret < 0 || (size_t)ret >= sz ) - {// overflow - buf[sz-1] = '\0';// always nul-terminate - return -1; - } - return ret; + va_list ap; + int ret; + + va_start(ap,fmt); + ret = vsnprintf(buf, sz, fmt, ap); + va_end(ap); + if (ret < 0 || (size_t)ret >= sz) { + // overflow + buf[sz-1] = '\0';// always nul-terminate + return -1; + } + return ret; } /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char* str, size_t pos) +int strline(const char *str, size_t pos) { - const char* target; - int line; - - if( str == NULL || pos == 0 ) - return 1; - - target = str+pos; - for( line = 1; ; ++line ) - { - str = strchr(str, '\n'); - if( str == NULL || target <= str ) - break;// found target line - ++str;// skip newline - } - return line; + const char *target; + int line; + + if (str == NULL || pos == 0) + return 1; + + target = str+pos; + for (line = 1; ; ++line) { + str = strchr(str, '\n'); + if (str == NULL || target <= str) + break;// found target line + ++str;// skip newline + } + return line; } /// Produces the hexadecimal representation of the given input. @@ -423,19 +410,18 @@ int strline(const char* str, size_t pos) /// @param output Output string /// @param input Binary input buffer /// @param count Number of bytes to convert -bool bin2hex(char* output, unsigned char* input, size_t count) +bool bin2hex(char *output, unsigned char *input, size_t count) { - char toHex[] = "0123456789abcdef"; - size_t i; - - for( i = 0; i < count; ++i ) - { - *output++ = toHex[(*input & 0xF0) >> 4]; - *output++ = toHex[(*input & 0x0F) >> 0]; - ++input; - } - *output = '\0'; - return true; + char toHex[] = "0123456789abcdef"; + size_t i; + + for (i = 0; i < count; ++i) { + *output++ = toHex[(*input & 0xF0) >> 4]; + *output++ = toHex[(*input & 0x0F) >> 0]; + ++input; + } + *output = '\0'; + return true; } @@ -446,146 +432,134 @@ bool bin2hex(char* output, unsigned char* input, size_t count) /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if already done, -1 on error. -int sv_parse_next(struct s_svstate* sv) +int sv_parse_next(struct s_svstate *sv) { - enum { - START_OF_FIELD, - PARSING_FIELD, - PARSING_C_ESCAPE, - END_OF_FIELD, - TERMINATE, - END - } state; - const char* str; - int len; - enum e_svopt opt; - char delim; - int i; - - if( sv == NULL ) - return -1;// error - - str = sv->str; - len = sv->len; - opt = sv->opt; - delim = sv->delim; - - // check opt - if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) ) - { - ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) ) - { - ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - - if( sv->done || str == NULL ) - { - sv->done = true; - return 0;// nothing to parse - } + enum { + START_OF_FIELD, + PARSING_FIELD, + PARSING_C_ESCAPE, + END_OF_FIELD, + TERMINATE, + END + } state; + const char *str; + int len; + enum e_svopt opt; + char delim; + int i; + + if (sv == NULL) + return -1;// error + + str = sv->str; + len = sv->len; + opt = sv->opt; + delim = sv->delim; + + // check opt + if (delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF))) { + ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + if (delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR))) { + ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + + if (sv->done || str == NULL) { + sv->done = true; + return 0;// nothing to parse + } #define IS_END() ( i >= len ) #define IS_DELIM() ( str[i] == delim ) #define IS_TERMINATOR() ( \ - ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ - ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ - ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) + ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ + ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ + ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' ) #define SET_FIELD_START() sv->start = i #define SET_FIELD_END() sv->end = i - i = sv->off; - state = START_OF_FIELD; - while( state != END ) - { - switch( state ) - { - case START_OF_FIELD:// record start of field and start parsing it - SET_FIELD_START(); - state = PARSING_FIELD; - break; - - case PARSING_FIELD:// skip field character - if( IS_END() || IS_DELIM() || IS_TERMINATOR() ) - state = END_OF_FIELD; - else if( IS_C_ESCAPE() ) - state = PARSING_C_ESCAPE; - else - ++i;// normal character - break; - - case PARSING_C_ESCAPE:// skip escape sequence (validates it too) - { - ++i;// '\\' - if( IS_END() ) - { - ShowError("sv_parse_next: empty escape sequence\n"); - return -1; - } - if( str[i] == 'x' ) - {// hex escape - ++i;// 'x' - if( IS_END() || !ISXDIGIT(str[i]) ) - { - ShowError("sv_parse_next: \\x with no following hex digits\n"); - return -1; - } - do{ - ++i;// hex digit - }while( !IS_END() && ISXDIGIT(str[i])); - } - else if( str[i] == '0' || str[i] == '1' || str[i] == '2' ) - {// octal escape - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - } - else if( strchr(SV_ESCAPE_C_SUPPORTED, str[i]) ) - {// supported escape character - ++i; - } - else - { - ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); - return -1; - } - state = PARSING_FIELD; - break; - } - - case END_OF_FIELD:// record end of field and stop - SET_FIELD_END(); - state = END; - if( IS_END() ) - ;// nothing else - else if( IS_DELIM() ) - ++i;// delim - else if( IS_TERMINATOR() ) - state = TERMINATE; - break; - - case TERMINATE: + i = sv->off; + state = START_OF_FIELD; + while (state != END) { + switch (state) { + case START_OF_FIELD:// record start of field and start parsing it + SET_FIELD_START(); + state = PARSING_FIELD; + break; + + case PARSING_FIELD:// skip field character + if (IS_END() || IS_DELIM() || IS_TERMINATOR()) + state = END_OF_FIELD; + else if (IS_C_ESCAPE()) + state = PARSING_C_ESCAPE; + else + ++i;// normal character + break; + + case PARSING_C_ESCAPE: { // skip escape sequence (validates it too) + ++i;// '\\' + if (IS_END()) { + ShowError("sv_parse_next: empty escape sequence\n"); + return -1; + } + if (str[i] == 'x') { + // hex escape + ++i;// 'x' + if (IS_END() || !ISXDIGIT(str[i])) { + ShowError("sv_parse_next: \\x with no following hex digits\n"); + return -1; + } + do { + ++i;// hex digit + } while (!IS_END() && ISXDIGIT(str[i])); + } else if (str[i] == '0' || str[i] == '1' || str[i] == '2') { + // octal escape + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + } else if (strchr(SV_ESCAPE_C_SUPPORTED, str[i])) { + // supported escape character + ++i; + } else { + ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); + return -1; + } + state = PARSING_FIELD; + break; + } + + case END_OF_FIELD:// record end of field and stop + SET_FIELD_END(); + state = END; + if (IS_END()) + ;// nothing else + else if (IS_DELIM()) + ++i;// delim + else if (IS_TERMINATOR()) + state = TERMINATE; + break; + + case TERMINATE: #if 0 - // skip line terminator - if( (opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n' ) - i += 2;// CRLF - else - ++i;// CR or LF + // skip line terminator + if ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') + i += 2;// CRLF + else + ++i;// CR or LF #endif - sv->done = true; - state = END; - break; - } - } - if( IS_END() ) - sv->done = true; - sv->off = i; + sv->done = true; + state = END; + break; + } + } + if (IS_END()) + sv->done = true; + sv->off = i; #undef IS_END #undef IS_DELIM @@ -594,7 +568,7 @@ int sv_parse_next(struct s_svstate* sv) #undef SET_FIELD_START #undef SET_FIELD_END - return 1; + return 1; } @@ -603,13 +577,13 @@ int sv_parse_next(struct s_svstate* sv) /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_pos can be NULL. /// If a line terminator is found, the end position is placed there. -/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] +/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] /// for the seconds field and so on. /// Unfilled positions are set to -1. -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -618,35 +592,34 @@ int sv_parse_next(struct s_svstate* sv) /// @param npos Size of the pos array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) +int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt) { - struct s_svstate sv; - int count; - - // initialize - if( out_pos == NULL ) npos = 0; - for( count = 0; count < npos; ++count ) - out_pos[count] = -1; - sv.str = str; - sv.len = len; - sv.off = startoff; - sv.opt = opt; - sv.delim = delim; - sv.done = false; - - // parse - count = 0; - if( npos > 0 ) out_pos[0] = startoff; - while( !sv.done ) - { - ++count; - if( sv_parse_next(&sv) <= 0 ) - return -1;// error - if( npos > count*2 ) out_pos[count*2] = sv.start; - if( npos > count*2+1 ) out_pos[count*2+1] = sv.end; - } - if( npos > 1 ) out_pos[1] = sv.off; - return count; + struct s_svstate sv; + int count; + + // initialize + if (out_pos == NULL) npos = 0; + for (count = 0; count < npos; ++count) + out_pos[count] = -1; + sv.str = str; + sv.len = len; + sv.off = startoff; + sv.opt = opt; + sv.delim = delim; + sv.done = false; + + // parse + count = 0; + if (npos > 0) out_pos[0] = startoff; + while (!sv.done) { + ++count; + if (sv_parse_next(&sv) <= 0) + return -1;// error + if (npos > count*2) out_pos[count*2] = sv.start; + if (npos > count*2+1) out_pos[count*2+1] = sv.end; + } + if (npos > 1) out_pos[1] = sv.off; + return count; } /// Splits a delim-separated string. @@ -655,11 +628,11 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_fields can be NULL. /// Fields that don't fit in out_fields are not nul-terminated. /// Extra entries in out_fields are filled with the end of the last field (empty string). -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -668,75 +641,64 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// @param nfields Size of the field array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) +int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt) { - int pos[1024]; - int i; - int done; - char* end; - int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); - - if( ret == -1 || out_fields == NULL || nfields <= 0 ) - return ret; // nothing to do - - // next line - end = str + pos[1]; - if( end[0] == '\0' ) - { - *out_fields = end; - } - else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = end[1] = '\0'; - *out_fields = end + 2; - } - else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else - { - ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); - return -1;// error - } - ++out_fields; - --nfields; - - // fields - i = 2; - done = 0; - while( done < ret && nfields > 0 ) - { - if( i < ARRAYLENGTH(pos) ) - {// split field - *out_fields = str + pos[i]; - end = str + pos[i+1]; - *end = '\0'; - // next field - i += 2; - ++done; - ++out_fields; - --nfields; - } - else - {// get more fields - sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); - i = 2; - } - } - // remaining fields - for( i = 0; i < nfields; ++i ) - out_fields[i] = end; - return ret; + int pos[1024]; + int i; + int done; + char *end; + int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); + + if (ret == -1 || out_fields == NULL || nfields <= 0) + return ret; // nothing to do + + // next line + end = str + pos[1]; + if (end[0] == '\0') { + *out_fields = end; + } else if ((opt&SV_TERMINATE_LF) && end[0] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else if ((opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = end[1] = '\0'; + *out_fields = end + 2; + } else if ((opt&SV_TERMINATE_CR) && end[0] == '\r') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else { + ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); + return -1;// error + } + ++out_fields; + --nfields; + + // fields + i = 2; + done = 0; + while (done < ret && nfields > 0) { + if (i < ARRAYLENGTH(pos)) { + // split field + *out_fields = str + pos[i]; + end = str + pos[i+1]; + *end = '\0'; + // next field + i += 2; + ++done; + ++out_fields; + --nfields; + } else { + // get more fields + sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); + i = 2; + } + } + // remaining fields + for (i = 0; i < nfields; ++i) + out_fields[i] = end; + return ret; } /// Escapes src to out_dest according to the format of the C compiler. @@ -748,69 +710,77 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in /// @param len Length of the source string /// @param escapes Extra characters to be escaped /// @return Length of the escaped string -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) +size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes) { - size_t i; - size_t j; - - if( out_dest == NULL ) - return 0;// nothing to do - if( src == NULL ) - {// nothing to escape - *out_dest = 0; - return 0; - } - if( escapes == NULL ) - escapes = ""; - - for( i = 0, j = 0; i < len; ++i ) - { - switch( src[i] ) - { - case '\0':// octal 0 - out_dest[j++] = '\\'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - break; - case '\r':// carriage return - out_dest[j++] = '\\'; - out_dest[j++] = 'r'; - break; - case '\n':// line feed - out_dest[j++] = '\\'; - out_dest[j++] = 'n'; - break; - case '\\':// escape character - out_dest[j++] = '\\'; - out_dest[j++] = '\\'; - break; - default: - if( strchr(escapes,src[i]) ) - {// escape - out_dest[j++] = '\\'; - switch( src[i] ) - { - case '\a': out_dest[j++] = 'a'; break; - case '\b': out_dest[j++] = 'b'; break; - case '\t': out_dest[j++] = 't'; break; - case '\v': out_dest[j++] = 'v'; break; - case '\f': out_dest[j++] = 'f'; break; - case '\?': out_dest[j++] = '?'; break; - default:// to octal - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); - break; - } - } - else - out_dest[j++] = src[i]; - break; - } - } - out_dest[j] = 0; - return j; + size_t i; + size_t j; + + if (out_dest == NULL) + return 0;// nothing to do + if (src == NULL) { + // nothing to escape + *out_dest = 0; + return 0; + } + if (escapes == NULL) + escapes = ""; + + for (i = 0, j = 0; i < len; ++i) { + switch (src[i]) { + case '\0':// octal 0 + out_dest[j++] = '\\'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + break; + case '\r':// carriage return + out_dest[j++] = '\\'; + out_dest[j++] = 'r'; + break; + case '\n':// line feed + out_dest[j++] = '\\'; + out_dest[j++] = 'n'; + break; + case '\\':// escape character + out_dest[j++] = '\\'; + out_dest[j++] = '\\'; + break; + default: + if (strchr(escapes,src[i])) { + // escape + out_dest[j++] = '\\'; + switch (src[i]) { + case '\a': + out_dest[j++] = 'a'; + break; + case '\b': + out_dest[j++] = 'b'; + break; + case '\t': + out_dest[j++] = 't'; + break; + case '\v': + out_dest[j++] = 'v'; + break; + case '\f': + out_dest[j++] = 'f'; + break; + case '\?': + out_dest[j++] = '?'; + break; + default:// to octal + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007))); + break; + } + } else + out_dest[j++] = src[i]; + break; + } + } + out_dest[j] = 0; + return j; } /// Unescapes src to out_dest according to the format of the C compiler. @@ -821,129 +791,135 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca /// @param src Source string /// @param len Length of the source string /// @return Length of the escaped string -size_t sv_unescape_c(char* out_dest, const char* src, size_t len) +size_t sv_unescape_c(char *out_dest, const char *src, size_t len) { - static unsigned char low2hex[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? - }; - size_t i; - size_t j; - - for( i = 0, j = 0; i < len; ) - { - if( src[i] == '\\' ) - { - ++i;// '\\' - if( i >= len ) - ShowWarning("sv_unescape_c: empty escape sequence\n"); - else if( src[i] == 'x' ) - {// hex escape sequence - unsigned char c = 0; - unsigned char inrange = 1; - - ++i;// 'x' - if( i >= len || !ISXDIGIT(src[i]) ) - { - ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); - continue; - } - do{ - if( c > 0x0F && inrange ) - { - ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); - inrange = 0; - } - c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit - ++i; - }while( i < len && ISXDIGIT(src[i]) ); - out_dest[j++] = (char)c; - } - else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) - {// octal escape sequence (255=0377) - unsigned char c = src[i]-'0'; - ++i;// '0', '1', '2' or '3' - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - out_dest[j++] = (char)c; - } - else - {// other escape sequence - if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL ) - ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); - switch( src[i] ) - { - case 'a': out_dest[j++] = '\a'; break; - case 'b': out_dest[j++] = '\b'; break; - case 't': out_dest[j++] = '\t'; break; - case 'n': out_dest[j++] = '\n'; break; - case 'v': out_dest[j++] = '\v'; break; - case 'f': out_dest[j++] = '\f'; break; - case 'r': out_dest[j++] = '\r'; break; - case '?': out_dest[j++] = '\?'; break; - default: out_dest[j++] = src[i]; break; - } - ++i;// escaped character - } - } - else - out_dest[j++] = src[i++];// normal character - } - out_dest[j] = 0; - return j; + static unsigned char low2hex[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? + }; + size_t i; + size_t j; + + for (i = 0, j = 0; i < len;) { + if (src[i] == '\\') { + ++i;// '\\' + if (i >= len) + ShowWarning("sv_unescape_c: empty escape sequence\n"); + else if (src[i] == 'x') { + // hex escape sequence + unsigned char c = 0; + unsigned char inrange = 1; + + ++i;// 'x' + if (i >= len || !ISXDIGIT(src[i])) { + ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); + continue; + } + do { + if (c > 0x0F && inrange) { + ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); + inrange = 0; + } + c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit + ++i; + } while (i < len && ISXDIGIT(src[i])); + out_dest[j++] = (char)c; + } else if (src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3') { + // octal escape sequence (255=0377) + unsigned char c = src[i]-'0'; + ++i;// '0', '1', '2' or '3' + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + out_dest[j++] = (char)c; + } else { + // other escape sequence + if (strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL) + ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); + switch (src[i]) { + case 'a': + out_dest[j++] = '\a'; + break; + case 'b': + out_dest[j++] = '\b'; + break; + case 't': + out_dest[j++] = '\t'; + break; + case 'n': + out_dest[j++] = '\n'; + break; + case 'v': + out_dest[j++] = '\v'; + break; + case 'f': + out_dest[j++] = '\f'; + break; + case 'r': + out_dest[j++] = '\r'; + break; + case '?': + out_dest[j++] = '\?'; + break; + default: + out_dest[j++] = src[i]; + break; + } + ++i;// escaped character + } + } else + out_dest[j++] = src[i++];// normal character + } + out_dest[j] = 0; + return j; } /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p) +const char *skip_escaped_c(const char *p) { - if( p && *p == '\\' ) - { - ++p; - switch( *p ) - { - case 'x':// hexadecimal - ++p; - while( ISXDIGIT(*p) ) - ++p; - break; - case '0': - case '1': - case '2': - case '3':// octal - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - break; - default: - if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) - ++p; - } - } - return p; + if (p && *p == '\\') { + ++p; + switch (*p) { + case 'x':// hexadecimal + ++p; + while (ISXDIGIT(*p)) + ++p; + break; + case '0': + case '1': + case '2': + case '3':// octal + ++p; + if (*p >= '0' && *p <= '7') + ++p; + if (*p >= '0' && *p <= '7') + ++p; + break; + default: + if (*p && strchr(SV_ESCAPE_C_SUPPORTED, *p)) + ++p; + } + } + return p; } @@ -958,78 +934,72 @@ const char* skip_escaped_c(const char* p) /// @param maxcols Maximum number of columns of a valid row /// @param parseproc User-supplied row processing function /// @return true on success, false if file could not be opened -bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)) +bool sv_readdb(const char *directory, const char *filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char *fields[], int columns, int current)) { - FILE* fp; - int lines = 0; - int entries = 0; - char** fields; // buffer for fields ([0] is reserved) - int columns, fields_length; - char path[1024], line[1024]; - char* match; - - snprintf(path, sizeof(path), "%s/%s", directory, filename); - - // open file - fp = fopen(path, "r"); - if( fp == NULL ) - { - ShowError("sv_readdb: can't read %s\n", path); - return false; - } - - // allocate enough memory for the maximum requested amount of columns plus the reserved one - fields_length = maxcols+1; - fields = (char**)aMalloc(fields_length*sizeof(char*)); - - // process rows one by one - while( fgets(line, sizeof(line), fp) ) - { - lines++; - - if( ( match = strstr(line, "//") ) != NULL ) - {// strip comments - match[0] = 0; - } - - //TODO: strip trailing whitespace - if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - - columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - - if( columns < mincols ) - { - ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); - continue; // not enough columns - } - if( columns > maxcols ) - { - ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols ); - continue; // too many columns - } - if( entries == maxrows ) - { - ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); - break; - } - - // parse this row - if( !parseproc(fields+1, columns, entries) ) - { - ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); - continue; // invalid row contents - } - - // success! - entries++; - } - - aFree(fields); - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); - - return true; + FILE *fp; + int lines = 0; + int entries = 0; + char **fields; // buffer for fields ([0] is reserved) + int columns, fields_length; + char path[1024], line[1024]; + char *match; + + snprintf(path, sizeof(path), "%s/%s", directory, filename); + + // open file + fp = fopen(path, "r"); + if (fp == NULL) { + ShowError("sv_readdb: can't read %s\n", path); + return false; + } + + // allocate enough memory for the maximum requested amount of columns plus the reserved one + fields_length = maxcols+1; + fields = (char **)aMalloc(fields_length*sizeof(char *)); + + // process rows one by one + while (fgets(line, sizeof(line), fp)) { + lines++; + + if ((match = strstr(line, "//")) != NULL) { + // strip comments + match[0] = 0; + } + + //TODO: strip trailing whitespace + if (line[0] == '\0' || line[0] == '\n' || line[0] == '\r') + continue; + + columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); + + if (columns < mincols) { + ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); + continue; // not enough columns + } + if (columns > maxcols) { + ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols); + continue; // too many columns + } + if (entries == maxrows) { + ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); + break; + } + + // parse this row + if (!parseproc(fields+1, columns, entries)) { + ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); + continue; // invalid row contents + } + + // success! + entries++; + } + + aFree(fields); + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); + + return true; } @@ -1039,129 +1009,126 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc // @author MouseJstr (original) /// Allocates a StringBuf -StringBuf* StringBuf_Malloc() +StringBuf *StringBuf_Malloc() { - StringBuf* self; - CREATE(self, StringBuf, 1); - StringBuf_Init(self); - return self; + StringBuf *self; + CREATE(self, StringBuf, 1); + StringBuf_Init(self); + return self; } /// Initializes a previously allocated StringBuf -void StringBuf_Init(StringBuf* self) +void StringBuf_Init(StringBuf *self) { - self->max_ = 1024; - self->ptr_ = self->buf_ = (char*)aMalloc(self->max_ + 1); + self->max_ = 1024; + self->ptr_ = self->buf_ = (char *)aMalloc(self->max_ + 1); } /// Appends the result of printf to the StringBuf -int StringBuf_Printf(StringBuf* self, const char* fmt, ...) +int StringBuf_Printf(StringBuf *self, const char *fmt, ...) { - int len; - va_list ap; + int len; + va_list ap; - va_start(ap, fmt); - len = StringBuf_Vprintf(self, fmt, ap); - va_end(ap); + va_start(ap, fmt); + len = StringBuf_Vprintf(self, fmt, ap); + va_end(ap); - return len; + return len; } /// Appends the result of vprintf to the StringBuf -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) +int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list ap) { - int n, size, off; - - for(;;) - { - va_list apcopy; - /* Try to print in the allocated space. */ - size = self->max_ - (self->ptr_ - self->buf_); - va_copy(apcopy, ap); - n = vsnprintf(self->ptr_, size, fmt, apcopy); - va_end(apcopy); - /* If that worked, return the length. */ - if( n > -1 && n < size ) - { - self->ptr_ += n; - return (int)(self->ptr_ - self->buf_); - } - /* Else try again with more space. */ - self->max_ *= 2; // twice the old size - off = (int)(self->ptr_ - self->buf_); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } + int n, size, off; + + for (;;) { + va_list apcopy; + /* Try to print in the allocated space. */ + size = self->max_ - (self->ptr_ - self->buf_); + va_copy(apcopy, ap); + n = vsnprintf(self->ptr_, size, fmt, apcopy); + va_end(apcopy); + /* If that worked, return the length. */ + if (n > -1 && n < size) { + self->ptr_ += n; + return (int)(self->ptr_ - self->buf_); + } + /* Else try again with more space. */ + self->max_ *= 2; // twice the old size + off = (int)(self->ptr_ - self->buf_); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } } /// Appends the contents of another StringBuf to the StringBuf -int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) +int StringBuf_Append(StringBuf *self, const StringBuf *sbuf) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)(sbuf->ptr_ - sbuf->buf_); - - if( needed >= available ) - { - int off = (int)(self->ptr_ - self->buf_); - self->max_ += needed; - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, sbuf->buf_, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)(sbuf->ptr_ - sbuf->buf_); + + if (needed >= available) { + int off = (int)(self->ptr_ - self->buf_); + self->max_ += needed; + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, sbuf->buf_, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Appends str to the StringBuf -int StringBuf_AppendStr(StringBuf* self, const char* str) +int StringBuf_AppendStr(StringBuf *self, const char *str) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)strlen(str); - - if( needed >= available ) - {// not enough space, expand the buffer (minimum expansion = 1024) - int off = (int)(self->ptr_ - self->buf_); - self->max_ += max(needed, 1024); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, str, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)strlen(str); + + if (needed >= available) { + // not enough space, expand the buffer (minimum expansion = 1024) + int off = (int)(self->ptr_ - self->buf_); + self->max_ += max(needed, 1024); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, str, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Returns the length of the data in the Stringbuf -int StringBuf_Length(StringBuf* self) +int StringBuf_Length(StringBuf *self) { - return (int)(self->ptr_ - self->buf_); + return (int)(self->ptr_ - self->buf_); } /// Returns the data in the StringBuf -char* StringBuf_Value(StringBuf* self) +char *StringBuf_Value(StringBuf *self) { - *self->ptr_ = '\0'; - return self->buf_; + *self->ptr_ = '\0'; + return self->buf_; } /// Clears the contents of the StringBuf -void StringBuf_Clear(StringBuf* self) +void StringBuf_Clear(StringBuf *self) { - self->ptr_ = self->buf_; + self->ptr_ = self->buf_; } /// Destroys the StringBuf -void StringBuf_Destroy(StringBuf* self) +void StringBuf_Destroy(StringBuf *self) { - aFree(self->buf_); - self->ptr_ = self->buf_ = 0; - self->max_ = 0; + aFree(self->buf_); + self->ptr_ = self->buf_ = 0; + self->max_ = 0; } // Frees a StringBuf returned by StringBuf_Malloc -void StringBuf_Free(StringBuf* self) +void StringBuf_Free(StringBuf *self) { - StringBuf_Destroy(self); - aFree(self); + StringBuf_Destroy(self); + aFree(self); } diff --git a/src/common/strlib.h b/src/common/strlib.h index bbc2c6105..ae4f688c2 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -11,66 +11,65 @@ #include #undef __USE_GNU -char* jstrescape (char* pt); -char* jstrescapecpy (char* pt, const char* spt); -int jmemescapecpy (char* pt, const char* spt, int size); +char *jstrescape(char *pt); +char *jstrescapecpy(char *pt, const char *spt); +int jmemescapecpy(char *pt, const char *spt, int size); -int remove_control_chars(char* str); -char* trim(char* str); -char* normalize_name(char* str,const char* delims); +int remove_control_chars(char *str); +char *trim(char *str); +char *normalize_name(char *str,const char *delims); const char *stristr(const char *haystack, const char *needle); #ifdef WIN32 #define HAVE_STRTOK_R #define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr)) -char* _strtok_r(char* s1, const char* s2, char** lasts); +char *_strtok_r(char *s1, const char *s2, char **lasts); #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) -size_t strnlen (const char* string, size_t maxlen); +size_t strnlen(const char *string, size_t maxlen); #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base); +uint64 strtoull(const char *str, char **endptr, int base); #endif -int e_mail_check(char* email); -int config_switch(const char* str); +int e_mail_check(char *email); +int config_switch(const char *str); /// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n); +char *safestrncpy(char *dst, const char *src, size_t n); /// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen); +size_t safestrnlen(const char *string, size_t maxlen); /// Works like snprintf, but always nul-terminates the buffer. /// Returns the size of the string (without nul-terminator) /// or -1 if the buffer is too small. -int safesnprintf(char* buf, size_t sz, const char* fmt, ...); +int safesnprintf(char *buf, size_t sz, const char *fmt, ...); /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char* str, size_t pos); +int strline(const char *str, size_t pos); /// Produces the hexadecimal representation of the given input. /// The output buffer must be at least count*2+1 in size. /// Returns true on success, false on failure. -bool bin2hex(char* output, unsigned char* input, size_t count); +bool bin2hex(char *output, unsigned char *input, size_t count); /// Bitfield determining the behaviour of sv_parse and sv_split. -typedef enum e_svopt -{ - // default: no escapes and no line terminator - SV_NOESCAPE_NOTERMINATE = 0, - // Escapes according to the C compiler. - SV_ESCAPE_C = 1, - // Line terminators - SV_TERMINATE_LF = 2, - SV_TERMINATE_CRLF = 4, - SV_TERMINATE_CR = 8, - // If sv_split keeps the end of line terminator, instead of replacing with '\0' - SV_KEEP_TERMINATOR = 16 +typedef enum e_svopt { + // default: no escapes and no line terminator + SV_NOESCAPE_NOTERMINATE = 0, + // Escapes according to the C compiler. + SV_ESCAPE_C = 1, + // Line terminators + SV_TERMINATE_LF = 2, + SV_TERMINATE_CRLF = 4, + SV_TERMINATE_CR = 8, + // If sv_split keeps the end of line terminator, instead of replacing with '\0' + SV_KEEP_TERMINATOR = 16 } e_svopt; /// Other escape sequences supported by the C compiler. @@ -78,16 +77,15 @@ typedef enum e_svopt /// Parse state. /// The field is [start,end[ -struct s_svstate -{ - const char* str; //< string to parse - int len; //< string length - int off; //< current offset in the string - int start; //< where the field starts - int end; //< where the field ends - enum e_svopt opt; //< parse options - char delim; //< field delimiter - bool done; //< if all the text has been parsed +struct s_svstate { + const char *str; //< string to parse + int len; //< string length + int off; //< current offset in the string + int start; //< where the field starts + int end; //< where the field ends + enum e_svopt opt; //< parse options + char delim; //< field delimiter + bool done; //< if all the text has been parsed }; /// Parses a single field in a delim-separated string. @@ -95,14 +93,14 @@ struct s_svstate /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if done, -1 on error. -int sv_parse_next(struct s_svstate* sv); +int sv_parse_next(struct s_svstate *sv); /// Parses a delim-separated string. /// Starts parsing at startoff and fills the pos array with position pairs. /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt); +int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt); /// Splits a delim-separated string. /// WARNING: this function modifies the input string @@ -110,46 +108,45 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt); +int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt); /// Escapes src to out_dest according to the format of the C compiler. /// Returns the length of the escaped string. /// out_dest should be len*4+1 in size. -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes); +size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes); /// Unescapes src to out_dest according to the format of the C compiler. /// Returns the length of the unescaped string. /// out_dest should be len+1 in size and can be the same buffer as src. -size_t sv_unescape_c(char* out_dest, const char* src, size_t len); +size_t sv_unescape_c(char *out_dest, const char *src, size_t len); /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p); +const char *skip_escaped_c(const char *p); /// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row. /// Tracks the progress of the operation (current line number, number of successfully processed rows). /// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read. -bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)); +bool sv_readdb(const char *directory, const char *filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char *fields[], int columns, int current)); /// StringBuf - dynamic string -struct StringBuf -{ - char *buf_; - char *ptr_; - unsigned int max_; +struct StringBuf { + char *buf_; + char *ptr_; + unsigned int max_; }; typedef struct StringBuf StringBuf; -StringBuf* StringBuf_Malloc(void); -void StringBuf_Init(StringBuf* self); -int StringBuf_Printf(StringBuf* self, const char* fmt, ...); -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list args); -int StringBuf_Append(StringBuf* self, const StringBuf *sbuf); -int StringBuf_AppendStr(StringBuf* self, const char* str); -int StringBuf_Length(StringBuf* self); -char* StringBuf_Value(StringBuf* self); -void StringBuf_Clear(StringBuf* self); -void StringBuf_Destroy(StringBuf* self); -void StringBuf_Free(StringBuf* self); +StringBuf *StringBuf_Malloc(void); +void StringBuf_Init(StringBuf *self); +int StringBuf_Printf(StringBuf *self, const char *fmt, ...); +int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list args); +int StringBuf_Append(StringBuf *self, const StringBuf *sbuf); +int StringBuf_AppendStr(StringBuf *self, const char *str); +int StringBuf_Length(StringBuf *self); +char *StringBuf_Value(StringBuf *self); +void StringBuf_Clear(StringBuf *self); +void StringBuf_Destroy(StringBuf *self); +void StringBuf_Free(StringBuf *self); #endif /* _STRLIB_H_ */ diff --git a/src/common/thread.c b/src/common/thread.c index 315b310b2..610ee394c 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -9,7 +9,7 @@ #ifdef WIN32 #include "../common/winapi.h" #define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) -#define __thread __declspec( thread ) +#define __thread __declspec( thread ) #else #include #include @@ -25,25 +25,25 @@ #include "thread.h" // When Compiling using MSC (on win32..) we know we have support in any case! -#ifdef _MSC_VER -#define HAS_TLS +#ifdef _MSC_VER +#define HAS_TLS #endif #define RA_THREADS_MAX 64 struct rAthread { - unsigned int myID; - - RATHREAD_PRIO prio; - rAthreadProc proc; - void *param; - - #ifdef WIN32 - HANDLE hThread; - #else - pthread_t hThread; - #endif + unsigned int myID; + + RATHREAD_PRIO prio; + rAthreadProc proc; + void *param; + +#ifdef WIN32 + HANDLE hThread; +#else + pthread_t hThread; +#endif }; @@ -57,95 +57,100 @@ __thread int g_rathread_ID = -1; /// static struct rAthread l_threads[RA_THREADS_MAX]; -void rathread_init(){ - register unsigned int i; - memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) ); - - for(i = 0; i < RA_THREADS_MAX; i++){ - l_threads[i].myID = i; - } +void rathread_init() +{ + register unsigned int i; + memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread)); + + for (i = 0; i < RA_THREADS_MAX; i++) { + l_threads[i].myID = i; + } - // now lets init thread id 0, which represnts the main thread + // now lets init thread id 0, which represnts the main thread #ifdef HAS_TLS - g_rathread_ID = 0; + g_rathread_ID = 0; #endif - l_threads[0].prio = RAT_PRIO_NORMAL; - l_threads[0].proc = (rAthreadProc)0xDEADCAFE; + l_threads[0].prio = RAT_PRIO_NORMAL; + l_threads[0].proc = (rAthreadProc)0xDEADCAFE; }//end: rathread_init() -void rathread_final(){ - register unsigned int i; - - // Unterminated Threads Left? - // Should'nt happen .. - // Kill 'em all! - // - for(i = 1; i < RA_THREADS_MAX; i++){ - if(l_threads[i].proc != NULL){ - ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); - rathread_destroy(&l_threads[i]); - } - } - - +void rathread_final() +{ + register unsigned int i; + + // Unterminated Threads Left? + // Should'nt happen .. + // Kill 'em all! + // + for (i = 1; i < RA_THREADS_MAX; i++) { + if (l_threads[i].proc != NULL) { + ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); + rathread_destroy(&l_threads[i]); + } + } + + }//end: rathread_final() // gets called whenever a thread terminated .. -static void rat_thread_terminated( rAthread handle ){ +static void rat_thread_terminated(rAthread handle) +{ - int id_backup = handle->myID; + int id_backup = handle->myID; - // Simply set all members to 0 (except the id) - memset(handle, 0x00, sizeof(struct rAthread)); - - handle->myID = id_backup; // done ;) + // Simply set all members to 0 (except the id) + memset(handle, 0x00, sizeof(struct rAthread)); + + handle->myID = id_backup; // done ;) }//end: rat_thread_terminated() #ifdef WIN32 -DWORD WINAPI _raThreadMainRedirector(LPVOID p){ +DWORD WINAPI _raThreadMainRedirector(LPVOID p) +{ #else -static void *_raThreadMainRedirector( void *p ){ - sigset_t set; // on Posix Thread platforms +static void *_raThreadMainRedirector(void *p) +{ + sigset_t set; // on Posix Thread platforms #endif - void *ret; - - // Update myID @ TLS to right id. + void *ret; + + // Update myID @ TLS to right id. #ifdef HAS_TLS - g_rathread_ID = ((rAthread)p)->myID; + g_rathread_ID = ((rAthread)p)->myID; #endif #ifndef WIN32 - // When using posix threads - // the threads inherits the Signal mask from the thread which's spawned - // this thread - // so we've to block everything we dont care about. - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGPIPE); - - pthread_sigmask(SIG_BLOCK, &set, NULL); - + // When using posix threads + // the threads inherits the Signal mask from the thread which's spawned + // this thread + // so we've to block everything we dont care about. + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + #endif - ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ; + ret = ((rAthread)p)->proc(((rAthread)p)->param) ; -#ifdef WIN32 - CloseHandle( ((rAthread)p)->hThread ); +#ifdef WIN32 + CloseHandle(((rAthread)p)->hThread); #endif - rat_thread_terminated( (rAthread)p ); + rat_thread_terminated((rAthread)p); #ifdef WIN32 - return (DWORD)ret; + return (DWORD)ret; #else - return ret; + return ret; #endif }//end: _raThreadMainRedirector() @@ -155,163 +160,172 @@ static void *_raThreadMainRedirector( void *p ){ /// /// API Level -/// -rAthread rathread_create( rAthreadProc entryPoint, void *param ){ - return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL ); +/// +rAthread rathread_create(rAthreadProc entryPoint, void *param) +{ + return rathread_createEx(entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL); }//end: rathread_create() -rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){ +rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio) +{ #ifndef WIN32 - pthread_attr_t attr; + pthread_attr_t attr; #endif - size_t tmp; - unsigned int i; - rAthread handle = NULL; - - - // given stacksize aligned to systems pagesize? - tmp = szStack % getpagesize(); - if(tmp != 0) - szStack += tmp; - - - // Get a free Thread Slot. - for(i = 0; i < RA_THREADS_MAX; i++){ - if(l_threads[i].proc == NULL){ - handle = &l_threads[i]; - break; - } - } - - if(handle == NULL){ - ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); - return NULL; - } - - - - handle->proc = entryPoint; - handle->param = param; + size_t tmp; + unsigned int i; + rAthread handle = NULL; + + + // given stacksize aligned to systems pagesize? + tmp = szStack % getpagesize(); + if (tmp != 0) + szStack += tmp; + + + // Get a free Thread Slot. + for (i = 0; i < RA_THREADS_MAX; i++) { + if (l_threads[i].proc == NULL) { + handle = &l_threads[i]; + break; + } + } + + if (handle == NULL) { + ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); + return NULL; + } + + + + handle->proc = entryPoint; + handle->param = param; #ifdef WIN32 - handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL); + handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void *)handle, 0, NULL); #else - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, szStack); - - if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){ - handle->proc = NULL; - handle->param = NULL; - return NULL; - } - pthread_attr_destroy(&attr); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, szStack); + + if (pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void *)handle) != 0) { + handle->proc = NULL; + handle->param = NULL; + return NULL; + } + pthread_attr_destroy(&attr); #endif - rathread_prio_set( handle, prio ); - - return handle; + rathread_prio_set(handle, prio); + + return handle; }//end: rathread_createEx -void rathread_destroy ( rAthread handle ){ +void rathread_destroy(rAthread handle) +{ #ifdef WIN32 - if( TerminateThread(handle->hThread, 0) != FALSE){ - CloseHandle(handle->hThread); - rat_thread_terminated(handle); - } + if (TerminateThread(handle->hThread, 0) != FALSE) { + CloseHandle(handle->hThread); + rat_thread_terminated(handle); + } #else - if( pthread_cancel( handle->hThread ) == 0){ - - // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. - // - pthread_join( handle->hThread, NULL ); - - // Tell our manager to release ressources ;) - rat_thread_terminated(handle); - } + if (pthread_cancel(handle->hThread) == 0) { + + // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. + // + pthread_join(handle->hThread, NULL); + + // Tell our manager to release ressources ;) + rat_thread_terminated(handle); + } #endif }//end: rathread_destroy() -rAthread rathread_self( ){ +rAthread rathread_self() +{ #ifdef HAS_TLS - rAthread handle = &l_threads[g_rathread_ID]; - - if(handle->proc != NULL) // entry point set, so its used! - return handle; + rAthread handle = &l_threads[g_rathread_ID]; + + if (handle->proc != NULL) // entry point set, so its used! + return handle; #else - // .. so no tls means we have to search the thread by its api-handle .. - int i; - - #ifdef WIN32 - HANDLE hSelf; - hSelf = GetCurrent = GetCurrentThread(); - #else - pthread_t hSelf; - hSelf = pthread_self(); - #endif - - for(i = 0; i < RA_THREADS_MAX; i++){ - if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) - return &l_threads[i]; - } - + // .. so no tls means we have to search the thread by its api-handle .. + int i; + +#ifdef WIN32 + HANDLE hSelf; + hSelf = GetCurrent = GetCurrentThread(); +#else + pthread_t hSelf; + hSelf = pthread_self(); +#endif + + for (i = 0; i < RA_THREADS_MAX; i++) { + if (l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) + return &l_threads[i]; + } + #endif - - return NULL; + + return NULL; }//end: rathread_self() -int rathread_get_tid(){ +int rathread_get_tid() +{ -#ifdef HAS_TLS - return g_rathread_ID; +#ifdef HAS_TLS + return g_rathread_ID; #else - // todo - #ifdef WIN32 - return (int)GetCurrentThreadId(); - #else - return (intptr_t)pthread_self(); - #endif - + // todo +#ifdef WIN32 + return (int)GetCurrentThreadId(); +#else + return (intptr_t)pthread_self(); +#endif + #endif - + }//end: rathread_get_tid() -bool rathread_wait( rAthread handle, void* *out_exitCode ){ - - // Hint: - // no thread data cleanup routine call here! - // its managed by the callProxy itself.. - // +bool rathread_wait(rAthread handle, void* *out_exitCode) +{ + + // Hint: + // no thread data cleanup routine call here! + // its managed by the callProxy itself.. + // #ifdef WIN32 - WaitForSingleObject(handle->hThread, INFINITE); - return true; + WaitForSingleObject(handle->hThread, INFINITE); + return true; #else - if(pthread_join(handle->hThread, out_exitCode) == 0) - return true; - return false; + if (pthread_join(handle->hThread, out_exitCode) == 0) + return true; + return false; #endif }//end: rathread_wait() -void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){ - handle->prio = RAT_PRIO_NORMAL; - //@TODO +void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio) +{ + handle->prio = RAT_PRIO_NORMAL; + //@TODO }//end: rathread_prio_set() -RATHREAD_PRIO rathread_prio_get( rAthread handle){ - return handle->prio; +RATHREAD_PRIO rathread_prio_get(rAthread handle) +{ + return handle->prio; }//end: rathread_prio_get() -void rathread_yield(){ -#ifdef WIN32 - SwitchToThread(); +void rathread_yield() +{ +#ifdef WIN32 + SwitchToThread(); #else - sched_yield(); -#endif + sched_yield(); +#endif }//end: rathread_yield() diff --git a/src/common/thread.h b/src/common/thread.h index a5a66e954..cfbfe689f 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -1,19 +1,19 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#pragma once +#pragma once #ifndef _rA_THREAD_H_ #define _rA_THREAD_H_ #include "../common/cbasetypes.h" typedef struct rAthread *rAthread; -typedef void* (*rAthreadProc)(void*); +typedef void *(*rAthreadProc)(void *); typedef enum RATHREAD_PRIO { - RAT_PRIO_LOW = 0, - RAT_PRIO_NORMAL, - RAT_PRIO_HIGH + RAT_PRIO_LOW = 0, + RAT_PRIO_NORMAL, + RAT_PRIO_HIGH } RATHREAD_PRIO; @@ -22,51 +22,51 @@ typedef enum RATHREAD_PRIO { * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint. - * + * * @return not NULL if success */ -rAthread rathread_create( rAthreadProc entryPoint, void *param ); +rAthread rathread_create(rAthreadProc entryPoint, void *param); -/** +/** * Creates a new Thread (with more creation options) * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint - * @param szStack - stack Size in bytes + * @param szStack - stack Size in bytes * @param prio - Priority of the Thread @ OS Scheduler.. * * @return not NULL if success */ -rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ); +rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio); /** * Destroys the given Thread immediatly * - * @note The Handle gets invalid after call! dont use it afterwards. + * @note The Handle gets invalid after call! dont use it afterwards. * * @param handle - thread to destroy. */ -void rathread_destroy ( rAthread handle ); +void rathread_destroy(rAthread handle); -/** +/** * Returns the thread handle of the thread calling this function - * + * * @note this wont work @ programms main thread - * @note the underlying implementation might not perform very well, cache the value received! - * + * @note the underlying implementation might not perform very well, cache the value received! + * * @return not NULL if success */ -rAthread rathread_self( ); +rAthread rathread_self(); /** - * Returns own thrad id (TID) + * Returns own thrad id (TID) * - * @note this is an unique identifier for the calling thread, and - * depends on platfrom / compiler, and may not be the systems Thread ID! + * @note this is an unique identifier for the calling thread, and + * depends on platfrom / compiler, and may not be the systems Thread ID! * * @return -1 when fails, otherwise >= 0 */ @@ -74,39 +74,39 @@ int rathread_get_tid(); /** - * Waits for the given thread to terminate + * Waits for the given thread to terminate * * @param handle - thread to wait (join) for * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated - * + * * @return true - if the given thread has been terminated. */ -bool rathread_wait( rAthread handle, void* *out_exitCode ); +bool rathread_wait(rAthread handle, void* *out_exitCode); -/** +/** * Sets the given PRIORITY @ OS Task Scheduler - * + * * @param handle - thread to set prio for * @param rio - the priority (RAT_PRIO_LOW ... ) */ -void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ); +void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio); -/** +/** * Gets the current Prio of the given trhead * * @param handle - the thread to get the prio for. */ -RATHREAD_PRIO rathread_prio_get( rAthread handle); +RATHREAD_PRIO rathread_prio_get(rAthread handle); /** * Tells the OS scheduler to yield the execution of the calling thread - * + * * @note: this will not "pause" the thread, - * it just allows the OS to spent the remaining time - * of the slice to another thread. + * it just allows the OS to spent the remaining time + * of the slice to another thread. */ void rathread_yield(); diff --git a/src/common/timer.c b/src/common/timer.c index c239a9d70..bb2458233 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -26,12 +26,12 @@ #define TIMER_MAX_INTERVAL 1000 // timers (array) -static struct TimerData* timer_data = NULL; +static struct TimerData *timer_data = NULL; static int timer_data_max = 0; static int timer_data_num = 0; // free timers (array) -static int* free_timer_list = NULL; +static int *free_timer_list = NULL; static int free_timer_list_max = 0; static int free_timer_list_pos = 0; @@ -53,85 +53,87 @@ time_t start_time; /*---------------------------- - * Timer debugging + * Timer debugging *----------------------------*/ struct timer_func_list { - struct timer_func_list* next; - TimerFunc func; - char* name; + struct timer_func_list *next; + TimerFunc func; + char *name; } *tfl_root = NULL; /// Sets the name of a timer function. -int add_timer_func_list(TimerFunc func, char* name) +int add_timer_func_list(TimerFunc func, char *name) { - struct timer_func_list* tfl; - - if (name) { - for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) - {// check suspicious cases - if( func == tfl->func ) - ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); - else if( strcmp(name,tfl->name) == 0 ) - ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); - } - CREATE(tfl,struct timer_func_list,1); - tfl->next = tfl_root; - tfl->func = func; - tfl->name = aStrdup(name); - tfl_root = tfl; - } - return 0; + struct timer_func_list *tfl; + + if (name) { + for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) { + // check suspicious cases + if (func == tfl->func) + ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); + else if (strcmp(name,tfl->name) == 0) + ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); + } + CREATE(tfl,struct timer_func_list,1); + tfl->next = tfl_root; + tfl->func = func; + tfl->name = aStrdup(name); + tfl_root = tfl; + } + return 0; } /// Returns the name of the timer function. -char* search_timer_func_list(TimerFunc func) +char *search_timer_func_list(TimerFunc func) { - struct timer_func_list* tfl; + struct timer_func_list *tfl; - for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) - if (func == tfl->func) - return tfl->name; + for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) + if (func == tfl->func) + return tfl->name; - return "unknown timer function"; + return "unknown timer function"; } /*---------------------------- - * Get tick time + * Get tick time *----------------------------*/ #if defined(ENABLE_RDTSC) static uint64 RDTSC_BEGINTICK = 0, RDTSC_CLOCK = 0; -static __inline uint64 _rdtsc(){ - register union{ - uint64 qw; - uint32 dw[2]; - } t; +static __inline uint64 _rdtsc() +{ + register union { + uint64 qw; + uint32 dw[2]; + } t; + + asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1])); - asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) ); - - return t.qw; + return t.qw; } -static void rdtsc_calibrate(){ - uint64 t1, t2; - int32 i; - - ShowStatus("Calibrating Timer Source, please wait... "); - - RDTSC_CLOCK = 0; - - for(i = 0; i < 5; i++){ - t1 = _rdtsc(); - usleep(1000000); //1000 MS - t2 = _rdtsc(); - RDTSC_CLOCK += (t2 - t1) / 1000; - } - RDTSC_CLOCK /= 5; - - RDTSC_BEGINTICK = _rdtsc(); - - ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) ); +static void rdtsc_calibrate() +{ + uint64 t1, t2; + int32 i; + + ShowStatus("Calibrating Timer Source, please wait... "); + + RDTSC_CLOCK = 0; + + for (i = 0; i < 5; i++) { + t1 = _rdtsc(); + usleep(1000000); //1000 MS + t2 = _rdtsc(); + RDTSC_CLOCK += (t2 - t1) / 1000; + } + RDTSC_CLOCK /= 5; + + RDTSC_BEGINTICK = _rdtsc(); + + ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000)); } #endif @@ -140,19 +142,19 @@ static void rdtsc_calibrate(){ static unsigned int tick(void) { #if defined(WIN32) - return GetTickCount(); + return GetTickCount(); #elif defined(ENABLE_RDTSC) - // - return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); - // + // + return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); + // #elif defined(HAVE_MONOTONIC_CLOCK) - struct timespec tval; - clock_gettime(CLOCK_MONOTONIC, &tval); - return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; + struct timespec tval; + clock_gettime(CLOCK_MONOTONIC, &tval); + return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; #else - struct timeval tval; - gettimeofday(&tval, NULL); - return tval.tv_sec * 1000 + tval.tv_usec / 1000; + struct timeval tval; + gettimeofday(&tval, NULL); + return tval.tv_sec * 1000 + tval.tv_usec / 1000; #endif } @@ -165,14 +167,14 @@ static int gettick_count = 1; unsigned int gettick_nocache(void) { - gettick_count = TICK_CACHE; - gettick_cache = tick(); - return gettick_cache; + gettick_count = TICK_CACHE; + gettick_cache = tick(); + return gettick_cache; } unsigned int gettick(void) { - return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache; + return (--gettick_count == 0) ? gettick_nocache() : gettick_cache; } ////////////////////////////// #else @@ -180,110 +182,108 @@ unsigned int gettick(void) // tick doesn't get cached unsigned int gettick_nocache(void) { - return tick(); + return tick(); } unsigned int gettick(void) { - return tick(); + return tick(); } ////////////////////////////////////////////////////////////////////////// #endif ////////////////////////////////////////////////////////////////////////// /*====================================== - * CORE : Timer Heap + * CORE : Timer Heap *--------------------------------------*/ /// Adds a timer to the timer_heap static void push_timer_heap(int tid) { - BHEAP_ENSURE(timer_heap, 1, 256); - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + BHEAP_ENSURE(timer_heap, 1, 256); + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); } /*========================== - * Timer Management + * Timer Management *--------------------------*/ /// Returns a free timer id. static int acquire_timer(void) { - int tid; - - // select a free timer - if (free_timer_list_pos) { - do { - tid = free_timer_list[--free_timer_list_pos]; - } while(tid >= timer_data_num && free_timer_list_pos > 0); - } else - tid = timer_data_num; - - // check available space - if( tid >= timer_data_num ) - for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); - if (tid >= timer_data_num && tid >= timer_data_max) - {// expand timer array - timer_data_max += 256; - if( timer_data ) - RECREATE(timer_data, struct TimerData, timer_data_max); - else - CREATE(timer_data, struct TimerData, timer_data_max); - memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); - } - - if( tid >= timer_data_num ) - timer_data_num = tid + 1; - - return tid; + int tid; + + // select a free timer + if (free_timer_list_pos) { + do { + tid = free_timer_list[--free_timer_list_pos]; + } while (tid >= timer_data_num && free_timer_list_pos > 0); + } else + tid = timer_data_num; + + // check available space + if (tid >= timer_data_num) + for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); + if (tid >= timer_data_num && tid >= timer_data_max) { + // expand timer array + timer_data_max += 256; + if (timer_data) + RECREATE(timer_data, struct TimerData, timer_data_max); + else + CREATE(timer_data, struct TimerData, timer_data_max); + memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); + } + + if (tid >= timer_data_num) + timer_data_num = tid + 1; + + return tid; } /// Starts a new timer that is deleted once it expires (single-use). /// Returns the timer's id. int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data) { - int tid; - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - timer_data[tid].interval = 1000; - push_timer_heap(tid); - - return tid; + int tid; + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + timer_data[tid].interval = 1000; + push_timer_heap(tid); + + return tid; } /// Starts a new timer that automatically restarts itself (infinite loop until manually removed). /// Returns the timer's id, or INVALID_TIMER if it fails. int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval) { - int tid; - - if( interval < 1 ) - { - ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); - return INVALID_TIMER; - } - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_INTERVAL; - timer_data[tid].interval = interval; - push_timer_heap(tid); - - return tid; + int tid; + + if (interval < 1) { + ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); + return INVALID_TIMER; + } + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + push_timer_heap(tid); + + return tid; } /// Retrieves internal timer data -const struct TimerData* get_timer(int tid) -{ - return ( tid >= 0 && tid < timer_data_num ) ? &timer_data[tid] : NULL; +const struct TimerData *get_timer(int tid) { + return (tid >= 0 && tid < timer_data_num) ? &timer_data[tid] : NULL; } /// Marks a timer specified by 'id' for immediate deletion once it expires. @@ -291,142 +291,135 @@ const struct TimerData* get_timer(int tid) /// Returns 0 on success, < 0 on failure. int delete_timer(int tid, TimerFunc func) { - if( tid < 0 || tid >= timer_data_num ) - { - ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); - return -1; - } - if( timer_data[tid].func != func ) - { - ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); - return -2; - } - - timer_data[tid].func = NULL; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - - return 0; + if (tid < 0 || tid >= timer_data_num) { + ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); + return -1; + } + if (timer_data[tid].func != func) { + ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); + return -2; + } + + timer_data[tid].func = NULL; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + + return 0; } /// Adjusts a timer's expiration time. /// Returns the new tick value, or -1 if it fails. int addtick_timer(int tid, unsigned int tick) { - return settick_timer(tid, timer_data[tid].tick+tick); + return settick_timer(tid, timer_data[tid].tick+tick); } /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). /// Returns the new tick value, or -1 if it fails. int settick_timer(int tid, unsigned int tick) { - size_t i; - - // search timer position - ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); - if( i == BHEAP_LENGTH(timer_heap) ) - { - ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); - return -1; - } - - if( (int)tick == -1 ) - tick = 0;// add 1ms to avoid the error value -1 - - if( timer_data[tid].tick == tick ) - return (int)tick;// nothing to do, already in propper position - - // pop and push adjusted timer - BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); - timer_data[tid].tick = tick; - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); - return (int)tick; + size_t i; + + // search timer position + ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); + if (i == BHEAP_LENGTH(timer_heap)) { + ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + return -1; + } + + if ((int)tick == -1) + tick = 0;// add 1ms to avoid the error value -1 + + if (timer_data[tid].tick == tick) + return (int)tick;// nothing to do, already in propper position + + // pop and push adjusted timer + BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); + timer_data[tid].tick = tick; + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + return (int)tick; } /// Executes all expired timers. /// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). int do_timer(unsigned int tick) { - int diff = TIMER_MAX_INTERVAL; // return value - - // process all timers one by one - while( BHEAP_LENGTH(timer_heap) ) - { - int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) - - diff = DIFF_TICK(timer_data[tid].tick, tick); - if( diff > 0 ) - break; // no more expired timers to process - - // remove timer - BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); - timer_data[tid].type |= TIMER_REMOVE_HEAP; - - if( timer_data[tid].func ) - { - if( diff < -1000 ) - // timer was delayed for more than 1 second, use current tick instead - timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); - else - timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); - } - - // in the case the function didn't change anything... - if( timer_data[tid].type & TIMER_REMOVE_HEAP ) - { - timer_data[tid].type &= ~TIMER_REMOVE_HEAP; - - switch( timer_data[tid].type ) - { - default: - case TIMER_ONCE_AUTODEL: - timer_data[tid].type = 0; - if (free_timer_list_pos >= free_timer_list_max) { - free_timer_list_max += 256; - RECREATE(free_timer_list,int,free_timer_list_max); - memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); - } - free_timer_list[free_timer_list_pos++] = tid; - break; - case TIMER_INTERVAL: - if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 ) - timer_data[tid].tick = tick + timer_data[tid].interval; - else - timer_data[tid].tick += timer_data[tid].interval; - push_timer_heap(tid); - break; - } - } - } - - return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); + int diff = TIMER_MAX_INTERVAL; // return value + + // process all timers one by one + while (BHEAP_LENGTH(timer_heap)) { + int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) + + diff = DIFF_TICK(timer_data[tid].tick, tick); + if (diff > 0) + break; // no more expired timers to process + + // remove timer + BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); + timer_data[tid].type |= TIMER_REMOVE_HEAP; + + if (timer_data[tid].func) { + if (diff < -1000) + // timer was delayed for more than 1 second, use current tick instead + timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); + else + timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); + } + + // in the case the function didn't change anything... + if (timer_data[tid].type & TIMER_REMOVE_HEAP) { + timer_data[tid].type &= ~TIMER_REMOVE_HEAP; + + switch (timer_data[tid].type) { + default: + case TIMER_ONCE_AUTODEL: + timer_data[tid].type = 0; + if (free_timer_list_pos >= free_timer_list_max) { + free_timer_list_max += 256; + RECREATE(free_timer_list,int,free_timer_list_max); + memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); + } + free_timer_list[free_timer_list_pos++] = tid; + break; + case TIMER_INTERVAL: + if (DIFF_TICK(timer_data[tid].tick, tick) < -1000) + timer_data[tid].tick = tick + timer_data[tid].interval; + else + timer_data[tid].tick += timer_data[tid].interval; + push_timer_heap(tid); + break; + } + } + } + + return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); } unsigned long get_uptime(void) { - return (unsigned long)difftime(time(NULL), start_time); + return (unsigned long)difftime(time(NULL), start_time); } void timer_init(void) { #if defined(ENABLE_RDTSC) - rdtsc_calibrate(); + rdtsc_calibrate(); #endif - time(&start_time); + time(&start_time); } void timer_final(void) { - struct timer_func_list *tfl; - struct timer_func_list *next; - - for( tfl=tfl_root; tfl != NULL; tfl = next ) { - next = tfl->next; // copy next pointer - aFree(tfl->name); // free structures - aFree(tfl); - } - - if (timer_data) aFree(timer_data); - BHEAP_CLEAR(timer_heap); - if (free_timer_list) aFree(free_timer_list); + struct timer_func_list *tfl; + struct timer_func_list *next; + + for (tfl=tfl_root; tfl != NULL; tfl = next) { + next = tfl->next; // copy next pointer + aFree(tfl->name); // free structures + aFree(tfl); + } + + if (timer_data) aFree(timer_data); + BHEAP_CLEAR(timer_heap); + if (free_timer_list) aFree(free_timer_list); } diff --git a/src/common/timer.h b/src/common/timer.h index d45c73d12..9b46927d8 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _TIMER_H_ -#define _TIMER_H_ +#ifndef _TIMER_H_ +#define _TIMER_H_ #include "../common/cbasetypes.h" @@ -12,9 +12,9 @@ // timer flags enum { - TIMER_ONCE_AUTODEL = 0x01, - TIMER_INTERVAL = 0x02, - TIMER_REMOVE_HEAP = 0x10, + TIMER_ONCE_AUTODEL = 0x01, + TIMER_INTERVAL = 0x02, + TIMER_REMOVE_HEAP = 0x10, }; // Struct declaration @@ -22,15 +22,15 @@ enum { typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data); struct TimerData { - unsigned int tick; - TimerFunc func; - int type; - int interval; - int heap_pos; - - // general-purpose storage - int id; - intptr_t data; + unsigned int tick; + TimerFunc func; + int type; + int interval; + int heap_pos; + + // general-purpose storage + int id; + intptr_t data; }; // Function prototype declaration @@ -40,13 +40,13 @@ unsigned int gettick_nocache(void); int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data); int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); -const struct TimerData* get_timer(int tid); +const struct TimerData *get_timer(int tid); int delete_timer(int tid, TimerFunc func); int addtick_timer(int tid, unsigned int tick); int settick_timer(int tid, unsigned int tick); -int add_timer_func_list(TimerFunc func, char* name); +int add_timer_func_list(TimerFunc func, char *name); unsigned long get_uptime(void); diff --git a/src/common/utils.c b/src/common/utils.c index 296df7e70..9d090f594 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -15,269 +15,262 @@ #include // floor() #ifdef WIN32 - #include "../common/winapi.h" - #ifndef F_OK - #define F_OK 0x0 - #endif /* F_OK */ +#include "../common/winapi.h" +#ifndef F_OK +#define F_OK 0x0 +#endif /* F_OK */ #else - #include - #include - #include +#include +#include +#include #endif /// Dumps given buffer into file pointed to by a handle. -void WriteDump(FILE* fp, const void* buffer, size_t length) +void WriteDump(FILE *fp, const void *buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for( i = 0; i < length; i++ ) - { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if( (i%16) == 15 ) - { - fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); - } - } - - if( (i%16) != 0 ) - { - ascii[i%16] = 0; - fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for (i = 0; i < length; i++) { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if ((i%16) == 15) { + fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); + } + } + + if ((i%16) != 0) { + ascii[i%16] = 0; + fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); + } } /// Dumps given buffer on the console. -void ShowDump(const void* buffer, size_t length) +void ShowDump(const void *buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for( i = 0; i < length; i++ ) - { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if( (i%16) == 15 ) - { - ShowDebug("%03X %s %s\n", i/16, hex, ascii); - } - } - - if( (i%16) != 0 ) - { - ascii[i%16] = 0; - ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for (i = 0; i < length; i++) { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if ((i%16) == 15) { + ShowDebug("%03X %s %s\n", i/16, hex, ascii); + } + } + + if ((i%16) != 0) { + ascii[i%16] = 0; + ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); + } } #ifdef WIN32 -static char* checkpath(char *path, const char *srcpath) -{ // just make sure the char*path is not const - char *p=path; - if(NULL!=path && NULL!=srcpath) - while(*srcpath) { - if (*srcpath=='/') { - *p++ = '\\'; - srcpath++; - } - else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char *checkpath(char *path, const char *srcpath) +{ + // just make sure the char*path is not const + char *p=path; + if (NULL!=path && NULL!=srcpath) + while (*srcpath) { + if (*srcpath=='/') { + *p++ = '\\'; + srcpath++; + } else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char*)) +void findfile(const char *p, const char *pat, void (func)(const char *)) { - WIN32_FIND_DATAA FindFileData; - HANDLE hFind; - char tmppath[MAX_PATH+1]; - - const char *path = (p ==NULL)? "." : p; - const char *pattern = (pat==NULL)? "" : pat; - - checkpath(tmppath,path); - if( PATHSEP != tmppath[strlen(tmppath)-1]) - strcat(tmppath, "\\*"); - else - strcat(tmppath, "*"); - - hFind = FindFirstFileA(tmppath, &FindFileData); - if (hFind != INVALID_HANDLE_VALUE) - { - do - { - if (strcmp(FindFileData.cFileName, ".") == 0) - continue; - if (strcmp(FindFileData.cFileName, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); - - if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { - func( tmppath ); - } - - - if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) - { - findfile(tmppath, pat, func); - } - }while (FindNextFileA(hFind, &FindFileData) != 0); - FindClose(hFind); - } - return; + WIN32_FIND_DATAA FindFileData; + HANDLE hFind; + char tmppath[MAX_PATH+1]; + + const char *path = (p ==NULL)? "." : p; + const char *pattern = (pat==NULL)? "" : pat; + + checkpath(tmppath,path); + if (PATHSEP != tmppath[strlen(tmppath)-1]) + strcat(tmppath, "\\*"); + else + strcat(tmppath, "*"); + + hFind = FindFirstFileA(tmppath, &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(FindFileData.cFileName, ".") == 0) + continue; + if (strcmp(FindFileData.cFileName, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); + + if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { + func(tmppath); + } + + + if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + findfile(tmppath, pat, func); + } + } while (FindNextFileA(hFind, &FindFileData) != 0); + FindClose(hFind); + } + return; } #else #define MAX_DIR_PATH 2048 -static char* checkpath(char *path, const char*srcpath) -{ // just make sure the char*path is not const - char *p=path; - if(NULL!=path && NULL!=srcpath) - while(*srcpath) { - if (*srcpath=='\\') { - *p++ = '/'; - srcpath++; - } - else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char *checkpath(char *path, const char *srcpath) +{ + // just make sure the char*path is not const + char *p=path; + if (NULL!=path && NULL!=srcpath) + while (*srcpath) { + if (*srcpath=='\\') { + *p++ = '/'; + srcpath++; + } else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char*)) +void findfile(const char *p, const char *pat, void (func)(const char *)) { - DIR* dir; // pointer to the scanned directory. - struct dirent* entry; // pointer to one directory entry. - struct stat dir_stat; // used by stat(). - char tmppath[MAX_DIR_PATH+1]; - char path[MAX_DIR_PATH+1]= "."; - const char *pattern = (pat==NULL)? "" : pat; - if(p!=NULL) strcpy(path,p); - - // open the directory for reading - dir = opendir( checkpath(path, path) ); - if (!dir) { - ShowError("Cannot read directory '%s'\n", path); - return; - } - - // scan the directory, traversing each sub-directory - // matching the pattern for each file name. - while ((entry = readdir(dir))) { - // skip the "." and ".." entries. - if (strcmp(entry->d_name, ".") == 0) - continue; - if (strcmp(entry->d_name, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); - - // check if the pattern matchs. - if (entry->d_name && strstr(entry->d_name, pattern)) { - func( tmppath ); - } - // check if it is a directory. - if (stat(tmppath, &dir_stat) == -1) { - ShowError("stat error %s\n': ", tmppath); - continue; - } - // is this a directory? - if (S_ISDIR(dir_stat.st_mode)) { - // decent recursivly - findfile(tmppath, pat, func); - } - }//end while - - closedir(dir); + DIR *dir; // pointer to the scanned directory. + struct dirent *entry; // pointer to one directory entry. + struct stat dir_stat; // used by stat(). + char tmppath[MAX_DIR_PATH+1]; + char path[MAX_DIR_PATH+1]= "."; + const char *pattern = (pat==NULL)? "" : pat; + if (p!=NULL) strcpy(path,p); + + // open the directory for reading + dir = opendir(checkpath(path, path)); + if (!dir) { + ShowError("Cannot read directory '%s'\n", path); + return; + } + + // scan the directory, traversing each sub-directory + // matching the pattern for each file name. + while ((entry = readdir(dir))) { + // skip the "." and ".." entries. + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); + + // check if the pattern matchs. + if (entry->d_name && strstr(entry->d_name, pattern)) { + func(tmppath); + } + // check if it is a directory. + if (stat(tmppath, &dir_stat) == -1) { + ShowError("stat error %s\n': ", tmppath); + continue; + } + // is this a directory? + if (S_ISDIR(dir_stat.st_mode)) { + // decent recursivly + findfile(tmppath, pat, func); + } + }//end while + + closedir(dir); } #endif -bool exists(const char* filename) +bool exists(const char *filename) { - return !access(filename, F_OK); + return !access(filename, F_OK); } uint8 GetByte(uint32 val, int idx) { - switch( idx ) - { - case 0: return (uint8)( (val & 0x000000FF) ); - case 1: return (uint8)( (val & 0x0000FF00) >> 0x08 ); - case 2: return (uint8)( (val & 0x00FF0000) >> 0x10 ); - case 3: return (uint8)( (val & 0xFF000000) >> 0x18 ); - default: + switch (idx) { + case 0: + return (uint8)((val & 0x000000FF)); + case 1: + return (uint8)((val & 0x0000FF00) >> 0x08); + case 2: + return (uint8)((val & 0x00FF0000) >> 0x10); + case 3: + return (uint8)((val & 0xFF000000) >> 0x18); + default: #if defined(DEBUG) - ShowDebug("GetByte: invalid index (idx=%d)\n", idx); + ShowDebug("GetByte: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 GetWord(uint32 val, int idx) { - switch( idx ) - { - case 0: return (uint16)( (val & 0x0000FFFF) ); - case 1: return (uint16)( (val & 0xFFFF0000) >> 0x10 ); - default: + switch (idx) { + case 0: + return (uint16)((val & 0x0000FFFF)); + case 1: + return (uint16)((val & 0xFFFF0000) >> 0x10); + default: #if defined(DEBUG) - ShowDebug("GetWord: invalid index (idx=%d)\n", idx); + ShowDebug("GetWord: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 MakeWord(uint8 byte0, uint8 byte1) { - return byte0 | (byte1 << 0x08); + return byte0 | (byte1 << 0x08); } uint32 MakeDWord(uint16 word0, uint16 word1) { - return - ( (uint32)(word0 ) )| - ( (uint32)(word1 << 0x10) ); + return + ((uint32)(word0))| + ((uint32)(word1 << 0x10)); } /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B) { - double result; + double result; - if( B == 0 ) - { - ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); - return ~0U; - } + if (B == 0) { + ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); + return ~0U; + } - result = 100 * ((double)A / (double)B); + result = 100 * ((double)A / (double)B); - if( result > UINT_MAX ) - { - ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); - return UINT_MAX; - } + if (result > UINT_MAX) { + ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); + return UINT_MAX; + } - return (unsigned int)floor(result); + return (unsigned int)floor(result); } diff --git a/src/common/utils.h b/src/common/utils.h index 8e39f2655..7f68e484e 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -8,11 +8,11 @@ #include // FILE* // generate a hex dump of the first 'length' bytes of 'buffer' -void WriteDump(FILE* fp, const void* buffer, size_t length); -void ShowDump(const void* buffer, size_t length); +void WriteDump(FILE *fp, const void *buffer, size_t length); +void ShowDump(const void *buffer, size_t length); -void findfile(const char *p, const char *pat, void (func)(const char*)); -bool exists(const char* filename); +void findfile(const char *p, const char *pat, void (func)(const char *)); +bool exists(const char *filename); //Caps values to min/max #define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a) diff --git a/src/common/winapi.h b/src/common/winapi.h index 7ce555049..dfb7d4588 100644 --- a/src/common/winapi.h +++ b/src/common/winapi.h @@ -2,12 +2,12 @@ #define STRICT -#define NTDDI_VERSION NTDDI_WIN2K +#define NTDDI_VERSION NTDDI_WIN2K #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 -#define _WIN32_IE 0x0600 +#define _WIN32_IE 0x0600 #define WIN32_LEAN_AND_MEAN -#define NOCOMM +#define NOCOMM #define NOKANJI #define NOHELP #define NOMCX diff --git a/src/config/const.h b/src/config/const.h index 5fb74e22e..11477e75f 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -13,85 +13,85 @@ */ /** - * "Sane Checks" to save you from compiling with cool bugs + * "Sane Checks" to save you from compiling with cool bugs **/ #if SECURE_NPCTIMEOUT_INTERVAL <= 0 - #error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) +#error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) #endif #if SECURE_NPCTIMEOUT < 0 - #error SECURE_NPCTIMEOUT cannot be lower than 0 +#error SECURE_NPCTIMEOUT cannot be lower than 0 #endif /** * Path within the /db folder to (non-)renewal specific db files **/ #ifdef RENEWAL - #define DBPATH "re/" +#define DBPATH "re/" #else - #define DBPATH "pre-re/" +#define DBPATH "pre-re/" #endif /** * DefType **/ #ifdef RENEWAL - typedef short defType; - #define DEFTYPE_MIN SHRT_MIN - #define DEFTYPE_MAX SHRT_MAX +typedef short defType; +#define DEFTYPE_MIN SHRT_MIN +#define DEFTYPE_MAX SHRT_MAX #else - typedef signed char defType; - #define DEFTYPE_MIN CHAR_MIN - #define DEFTYPE_MAX CHAR_MAX +typedef signed char defType; +#define DEFTYPE_MIN CHAR_MIN +#define DEFTYPE_MAX CHAR_MAX #endif /* pointer size fix which fixes several gcc warnings */ #ifdef __64BIT__ - #define __64BPRTSIZE(y) (intptr)y +#define __64BPRTSIZE(y) (intptr)y #else - #define __64BPRTSIZE(y) y +#define __64BPRTSIZE(y) y #endif /* ATCMD_FUNC(mobinfo) HIT and FLEE calculations */ #ifdef RENEWAL - #define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) - #define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) +#define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) +#define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) #else - #define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) - #define MOB_HIT(mob) ( mob->lv + mob->status.dex ) +#define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) +#define MOB_HIT(mob) ( mob->lv + mob->status.dex ) #endif /* Renewal's dmg level modifier, used as a macro for a easy way to turn off. */ #ifdef RENEWAL_LVDMG - #define RE_LVL_DMOD(val) \ - if( status_get_lv(src) > 100 && val > 0 ) \ - skillratio = skillratio * status_get_lv(src) / val; - #define RE_LVL_MDMOD(val) \ - if( status_get_lv(src) > 100 && val > 0) \ - md.damage = md.damage * status_get_lv(src) / val; - /* ranger traps special */ - #define RE_LVL_TMDMOD() \ - if( status_get_lv(src) > 100 ) \ - md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; +#define RE_LVL_DMOD(val) \ + if( status_get_lv(src) > 100 && val > 0 ) \ + skillratio = skillratio * status_get_lv(src) / val; +#define RE_LVL_MDMOD(val) \ + if( status_get_lv(src) > 100 && val > 0) \ + md.damage = md.damage * status_get_lv(src) / val; +/* ranger traps special */ +#define RE_LVL_TMDMOD() \ + if( status_get_lv(src) > 100 ) \ + md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; #else - #define RE_LVL_DMOD(val) - #define RE_LVL_MDMOD(val) - #define RE_LVL_TMDMOD() +#define RE_LVL_DMOD(val) +#define RE_LVL_MDMOD(val) +#define RE_LVL_TMDMOD() #endif /* Feb 1st 2012 */ #if PACKETVER >= 20120201 - #define NEW_CARTS - #define MAX_CARTS 9 +#define NEW_CARTS +#define MAX_CARTS 9 #else - #define MAX_CARTS 5 +#define MAX_CARTS 5 #endif // Renewal variable cast time reduction #ifdef RENEWAL_CAST - #define VARCAST_REDUCTION(val){ \ - if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ - time = time * (1 - (float)min(val, 100) / 100); \ - } +#define VARCAST_REDUCTION(val){ \ + if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ + time = time * (1 - (float)min(val, 100) / 100); \ + } #endif /** * End of File diff --git a/src/login/account.h b/src/login/account.h index 1b567be70..22e31d799 100644 --- a/src/login/account.h +++ b/src/login/account.h @@ -12,144 +12,141 @@ typedef struct AccountDBIterator AccountDBIterator; // standard engines -AccountDB* account_db_sql(void); +AccountDB *account_db_sql(void); // extra engines (will probably use the other txt functions) #define ACCOUNTDB_CONSTRUCTOR_(engine) account_db_##engine #define ACCOUNTDB_CONSTRUCTOR(engine) ACCOUNTDB_CONSTRUCTOR_(engine) #ifdef ACCOUNTDB_ENGINE_0 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); #endif #ifdef ACCOUNTDB_ENGINE_1 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); #endif #ifdef ACCOUNTDB_ENGINE_2 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); #endif #ifdef ACCOUNTDB_ENGINE_3 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); #endif #ifdef ACCOUNTDB_ENGINE_4 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); #endif -struct mmo_account -{ - int account_id; - char userid[NAME_LENGTH]; - char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - char sex; // gender (M/F/S) - char email[40]; // e-mail (by default: a@a.com) - int group_id; // player group id - unsigned int state; // packet 0x006a value + 1 (0: compte OK) - time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) - time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) - unsigned int logincount;// number of successful auth attempts - char lastlogin[24]; // date+time of last successful login - char last_ip[16]; // save of last IP of connection - char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) +struct mmo_account { + int account_id; + char userid[NAME_LENGTH]; + char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + char sex; // gender (M/F/S) + char email[40]; // e-mail (by default: a@a.com) + int group_id; // player group id + unsigned int state; // packet 0x006a value + 1 (0: compte OK) + time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) + time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) + unsigned int logincount;// number of successful auth attempts + char lastlogin[24]; // date+time of last successful login + char last_ip[16]; // save of last IP of connection + char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) }; -struct AccountDBIterator -{ - /// Destroys this iterator, releasing all allocated memory (including itself). - /// - /// @param self Iterator - void (*destroy)(AccountDBIterator* self); +struct AccountDBIterator { + /// Destroys this iterator, releasing all allocated memory (including itself). + /// + /// @param self Iterator + void (*destroy)(AccountDBIterator *self); - /// Fetches the next account in the database. - /// Fills acc with the account data. - /// @param self Iterator - /// @param acc Account data - /// @return true if successful - bool (*next)(AccountDBIterator* self, struct mmo_account* acc); + /// Fetches the next account in the database. + /// Fills acc with the account data. + /// @param self Iterator + /// @param acc Account data + /// @return true if successful + bool (*next)(AccountDBIterator *self, struct mmo_account *acc); }; -struct AccountDB -{ - /// Initializes this database, making it ready for use. - /// Call this after setting the properties. - /// - /// @param self Database - /// @return true if successful - bool (*init)(AccountDB* self); - - /// Destroys this database, releasing all allocated memory (including itself). - /// - /// @param self Database - void (*destroy)(AccountDB* self); - - /// Gets a property from this database. - /// These read-only properties must be implemented: - /// "engine.name" -> "txt", "sql", ... - /// "engine.version" -> internal version - /// "engine.comment" -> anything (suggestion: description or specs of the engine) - /// - /// @param self Database - /// @param key Property name - /// @param buf Buffer for the value - /// @param buflen Buffer length - /// @return true if successful - bool (*get_property)(AccountDB* self, const char* key, char* buf, size_t buflen); - - /// Sets a property in this database. - /// - /// @param self Database - /// @param key Property name - /// @param value Property value - /// @return true if successful - bool (*set_property)(AccountDB* self, const char* key, const char* value); - - /// Creates a new account in this database. - /// If acc->account_id is not -1, the provided value will be used. - /// Otherwise the account_id will be auto-generated and written to acc->account_id. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*create)(AccountDB* self, struct mmo_account* acc); - - /// Removes an account from this database. - /// - /// @param self Database - /// @param account_id Account id - /// @return true if successful - bool (*remove)(AccountDB* self, const int account_id); - - /// Modifies the data of an existing account. - /// Uses acc->account_id to identify the account. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*save)(AccountDB* self, const struct mmo_account* acc); - - /// Finds an account with account_id and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param account_id Target account id - /// @return true if successful - bool (*load_num)(AccountDB* self, struct mmo_account* acc, const int account_id); - - /// Finds an account with userid and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param userid Target username - /// @return true if successful - bool (*load_str)(AccountDB* self, struct mmo_account* acc, const char* userid); - - /// Returns a new forward iterator. - /// - /// @param self Database - /// @return Iterator - AccountDBIterator* (*iterator)(AccountDB* self); +struct AccountDB { + /// Initializes this database, making it ready for use. + /// Call this after setting the properties. + /// + /// @param self Database + /// @return true if successful + bool (*init)(AccountDB *self); + + /// Destroys this database, releasing all allocated memory (including itself). + /// + /// @param self Database + void (*destroy)(AccountDB *self); + + /// Gets a property from this database. + /// These read-only properties must be implemented: + /// "engine.name" -> "txt", "sql", ... + /// "engine.version" -> internal version + /// "engine.comment" -> anything (suggestion: description or specs of the engine) + /// + /// @param self Database + /// @param key Property name + /// @param buf Buffer for the value + /// @param buflen Buffer length + /// @return true if successful + bool (*get_property)(AccountDB *self, const char *key, char *buf, size_t buflen); + + /// Sets a property in this database. + /// + /// @param self Database + /// @param key Property name + /// @param value Property value + /// @return true if successful + bool (*set_property)(AccountDB *self, const char *key, const char *value); + + /// Creates a new account in this database. + /// If acc->account_id is not -1, the provided value will be used. + /// Otherwise the account_id will be auto-generated and written to acc->account_id. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*create)(AccountDB *self, struct mmo_account *acc); + + /// Removes an account from this database. + /// + /// @param self Database + /// @param account_id Account id + /// @return true if successful + bool (*remove)(AccountDB *self, const int account_id); + + /// Modifies the data of an existing account. + /// Uses acc->account_id to identify the account. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*save)(AccountDB *self, const struct mmo_account *acc); + + /// Finds an account with account_id and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param account_id Target account id + /// @return true if successful + bool (*load_num)(AccountDB *self, struct mmo_account *acc, const int account_id); + + /// Finds an account with userid and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param userid Target username + /// @return true if successful + bool (*load_str)(AccountDB *self, struct mmo_account *acc, const char *userid); + + /// Returns a new forward iterator. + /// + /// @param self Database + /// @return Iterator + AccountDBIterator *(*iterator)(AccountDB *self); }; diff --git a/src/login/account_sql.c b/src/login/account_sql.c index 5073941e2..6e56d4688 100644 --- a/src/login/account_sql.c +++ b/src/login/account_sql.c @@ -15,98 +15,96 @@ #define ACCOUNT_SQL_DB_VERSION 20110114 /// internal structure -typedef struct AccountDB_SQL -{ - AccountDB vtable; // public interface - - Sql* accounts; // SQL accounts storage - - // global sql settings - char global_db_hostname[32]; - uint16 global_db_port; - char global_db_username[32]; - char global_db_password[32]; - char global_db_database[32]; - char global_codepage[32]; - // local sql settings - char db_hostname[32]; - uint16 db_port; - char db_username[32]; - char db_password[32]; - char db_database[32]; - char codepage[32]; - // other settings - bool case_sensitive; - char account_db[32]; - char accreg_db[32]; +typedef struct AccountDB_SQL { + AccountDB vtable; // public interface + + Sql *accounts; // SQL accounts storage + + // global sql settings + char global_db_hostname[32]; + uint16 global_db_port; + char global_db_username[32]; + char global_db_password[32]; + char global_db_database[32]; + char global_codepage[32]; + // local sql settings + char db_hostname[32]; + uint16 db_port; + char db_username[32]; + char db_password[32]; + char db_database[32]; + char codepage[32]; + // other settings + bool case_sensitive; + char account_db[32]; + char accreg_db[32]; } AccountDB_SQL; /// internal structure -typedef struct AccountDBIterator_SQL -{ - AccountDBIterator vtable; // public interface +typedef struct AccountDBIterator_SQL { + AccountDBIterator vtable; // public interface - AccountDB_SQL* db; - int last_account_id; + AccountDB_SQL *db; + int last_account_id; } AccountDBIterator_SQL; /// internal functions -static bool account_db_sql_init(AccountDB* self); -static void account_db_sql_destroy(AccountDB* self); -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen); -static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value); -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc); -static bool account_db_sql_remove(AccountDB* self, const int account_id); -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc); -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id); -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid); -static AccountDBIterator* account_db_sql_iterator(AccountDB* self); -static void account_db_sql_iter_destroy(AccountDBIterator* self); -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc); - -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id); -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new); +static bool account_db_sql_init(AccountDB *self); +static void account_db_sql_destroy(AccountDB *self); +static bool account_db_sql_get_property(AccountDB *self, const char *key, char *buf, size_t buflen); +static bool account_db_sql_set_property(AccountDB *self, const char *option, const char *value); +static bool account_db_sql_create(AccountDB *self, struct mmo_account *acc); +static bool account_db_sql_remove(AccountDB *self, const int account_id); +static bool account_db_sql_save(AccountDB *self, const struct mmo_account *acc); +static bool account_db_sql_load_num(AccountDB *self, struct mmo_account *acc, const int account_id); +static bool account_db_sql_load_str(AccountDB *self, struct mmo_account *acc, const char *userid); +static AccountDBIterator *account_db_sql_iterator(AccountDB *self); +static void account_db_sql_iter_destroy(AccountDBIterator *self); +static bool account_db_sql_iter_next(AccountDBIterator *self, struct mmo_account *acc); + +static bool mmo_auth_fromsql(AccountDB_SQL *db, struct mmo_account *acc, int account_id); +static bool mmo_auth_tosql(AccountDB_SQL *db, const struct mmo_account *acc, bool is_new); /// public constructor -AccountDB* account_db_sql(void) +AccountDB *account_db_sql(void) { - AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL)); - - // set up the vtable - db->vtable.init = &account_db_sql_init; - db->vtable.destroy = &account_db_sql_destroy; - db->vtable.get_property = &account_db_sql_get_property; - db->vtable.set_property = &account_db_sql_set_property; - db->vtable.save = &account_db_sql_save; - db->vtable.create = &account_db_sql_create; - db->vtable.remove = &account_db_sql_remove; - db->vtable.load_num = &account_db_sql_load_num; - db->vtable.load_str = &account_db_sql_load_str; - db->vtable.iterator = &account_db_sql_iterator; - - // initialize to default values - db->accounts = NULL; - // global sql settings - safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname)); - db->global_db_port = 3306; - safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username)); - safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password)); - safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database)); - safestrncpy(db->global_codepage, "", sizeof(db->global_codepage)); - // local sql settings - safestrncpy(db->db_hostname, "", sizeof(db->db_hostname)); - db->db_port = 3306; - safestrncpy(db->db_username, "", sizeof(db->db_username)); - safestrncpy(db->db_password, "", sizeof(db->db_password)); - safestrncpy(db->db_database, "", sizeof(db->db_database)); - safestrncpy(db->codepage, "", sizeof(db->codepage)); - // other settings - db->case_sensitive = false; - safestrncpy(db->account_db, "login", sizeof(db->account_db)); - safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db)); - - return &db->vtable; + AccountDB_SQL *db = (AccountDB_SQL *)aCalloc(1, sizeof(AccountDB_SQL)); + + // set up the vtable + db->vtable.init = &account_db_sql_init; + db->vtable.destroy = &account_db_sql_destroy; + db->vtable.get_property = &account_db_sql_get_property; + db->vtable.set_property = &account_db_sql_set_property; + db->vtable.save = &account_db_sql_save; + db->vtable.create = &account_db_sql_create; + db->vtable.remove = &account_db_sql_remove; + db->vtable.load_num = &account_db_sql_load_num; + db->vtable.load_str = &account_db_sql_load_str; + db->vtable.iterator = &account_db_sql_iterator; + + // initialize to default values + db->accounts = NULL; + // global sql settings + safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname)); + db->global_db_port = 3306; + safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username)); + safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password)); + safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database)); + safestrncpy(db->global_codepage, "", sizeof(db->global_codepage)); + // local sql settings + safestrncpy(db->db_hostname, "", sizeof(db->db_hostname)); + db->db_port = 3306; + safestrncpy(db->db_username, "", sizeof(db->db_username)); + safestrncpy(db->db_password, "", sizeof(db->db_password)); + safestrncpy(db->db_database, "", sizeof(db->db_database)); + safestrncpy(db->codepage, "", sizeof(db->codepage)); + // other settings + db->case_sensitive = false; + safestrncpy(db->account_db, "login", sizeof(db->account_db)); + safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db)); + + return &db->vtable; } @@ -114,567 +112,532 @@ AccountDB* account_db_sql(void) /// establishes database connection -static bool account_db_sql_init(AccountDB* self) +static bool account_db_sql_init(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle; - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - db->accounts = Sql_Malloc(); - sql_handle = db->accounts; - - if( db->db_hostname[0] != '\0' ) - {// local settings - username = db->db_username; - password = db->db_password; - hostname = db->db_hostname; - port = db->db_port; - database = db->db_database; - codepage = db->codepage; - } - else - {// global settings - username = db->global_db_username; - password = db->global_db_password; - hostname = db->global_db_hostname; - port = db->global_db_port; - database = db->global_db_database; - codepage = db->global_codepage; - } - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(db->accounts); - db->accounts = NULL; - return false; - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - return true; + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle; + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + db->accounts = Sql_Malloc(); + sql_handle = db->accounts; + + if (db->db_hostname[0] != '\0') { + // local settings + username = db->db_username; + password = db->db_password; + hostname = db->db_hostname; + port = db->db_port; + database = db->db_database; + codepage = db->codepage; + } else { + // global settings + username = db->global_db_username; + password = db->global_db_password; + hostname = db->global_db_hostname; + port = db->global_db_port; + database = db->global_db_database; + codepage = db->global_codepage; + } + + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(db->accounts); + db->accounts = NULL; + return false; + } + + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + return true; } /// disconnects from database -static void account_db_sql_destroy(AccountDB* self) +static void account_db_sql_destroy(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; + AccountDB_SQL *db = (AccountDB_SQL *)self; - Sql_Free(db->accounts); - db->accounts = NULL; - aFree(db); + Sql_Free(db->accounts); + db->accounts = NULL; + aFree(db); } /// Gets a property from this database. -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen) +static bool account_db_sql_get_property(AccountDB *self, const char *key, char *buf, size_t buflen) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - signature = "engine."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "name") == 0 ) - safesnprintf(buf, buflen, "sql"); - else - if( strcmpi(key, "version") == 0 ) - safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION); - else - if( strcmpi(key, "comment") == 0 ) - safesnprintf(buf, buflen, "SQL Account Database"); - else - return false;// not found - return true; - } - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->global_db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_codepage); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->codepage); - else - if( strcmpi(key, "case_sensitive") == 0 ) - safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); - else - if( strcmpi(key, "account_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->account_db); - else - if( strcmpi(key, "accreg_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->accreg_db); - else - return false;// not found - return true; - } - - return false;// not found + AccountDB_SQL *db = (AccountDB_SQL *)self; + const char *signature; + + signature = "engine."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "name") == 0) + safesnprintf(buf, buflen, "sql"); + else if (strcmpi(key, "version") == 0) + safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION); + else if (strcmpi(key, "comment") == 0) + safesnprintf(buf, buflen, "SQL Account Database"); + else + return false;// not found + return true; + } + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_hostname); + else if (strcmpi(key, "db_port") == 0) + safesnprintf(buf, buflen, "%d", db->global_db_port); + else if (strcmpi(key, "db_username") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_username); + else if (strcmpi(key, "db_password") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_password); + else if (strcmpi(key, "db_database") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_database); + else if (strcmpi(key, "codepage") == 0) + safesnprintf(buf, buflen, "%s", db->global_codepage); + else + return false;// not found + return true; + } + + signature = "account.sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safesnprintf(buf, buflen, "%s", db->db_hostname); + else if (strcmpi(key, "db_port") == 0) + safesnprintf(buf, buflen, "%d", db->db_port); + else if (strcmpi(key, "db_username") == 0) + safesnprintf(buf, buflen, "%s", db->db_username); + else if (strcmpi(key, "db_password") == 0) + safesnprintf(buf, buflen, "%s", db->db_password); + else if (strcmpi(key, "db_database") == 0) + safesnprintf(buf, buflen, "%s", db->db_database); + else if (strcmpi(key, "codepage") == 0) + safesnprintf(buf, buflen, "%s", db->codepage); + else if (strcmpi(key, "case_sensitive") == 0) + safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); + else if (strcmpi(key, "account_db") == 0) + safesnprintf(buf, buflen, "%s", db->account_db); + else if (strcmpi(key, "accreg_db") == 0) + safesnprintf(buf, buflen, "%s", db->accreg_db); + else + return false;// not found + return true; + } + + return false;// not found } /// if the option is supported, adjusts the internal state -static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value) +static bool account_db_sql_set_property(AccountDB *self, const char *key, const char *value) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - - signature = "sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->global_db_username, value, sizeof(db->global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->global_db_password, value, sizeof(db->global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->global_db_database, value, sizeof(db->global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->global_codepage, value, sizeof(db->global_codepage)); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->db_hostname, value, sizeof(db->db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->db_username, value, sizeof(db->db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->db_password, value, sizeof(db->db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->db_database, value, sizeof(db->db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->codepage, value, sizeof(db->codepage)); - else - if( strcmpi(key, "case_sensitive") == 0 ) - db->case_sensitive = config_switch(value); - else - if( strcmpi(key, "account_db") == 0 ) - safestrncpy(db->account_db, value, sizeof(db->account_db)); - else - if( strcmpi(key, "accreg_db") == 0 ) - safestrncpy(db->accreg_db, value, sizeof(db->accreg_db)); - else - return false;// not found - return true; - } - - return false;// not found + AccountDB_SQL *db = (AccountDB_SQL *)self; + const char *signature; + + + signature = "sql."; + if (strncmp(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + db->global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(db->global_db_username, value, sizeof(db->global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(db->global_db_password, value, sizeof(db->global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(db->global_db_database, value, sizeof(db->global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(db->global_codepage, value, sizeof(db->global_codepage)); + else + return false;// not found + return true; + } + + signature = "account.sql."; + if (strncmp(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(db->db_hostname, value, sizeof(db->db_hostname)); + else if (strcmpi(key, "db_port") == 0) + db->db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(db->db_username, value, sizeof(db->db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(db->db_password, value, sizeof(db->db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(db->db_database, value, sizeof(db->db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(db->codepage, value, sizeof(db->codepage)); + else if (strcmpi(key, "case_sensitive") == 0) + db->case_sensitive = config_switch(value); + else if (strcmpi(key, "account_db") == 0) + safestrncpy(db->account_db, value, sizeof(db->account_db)); + else if (strcmpi(key, "accreg_db") == 0) + safestrncpy(db->accreg_db, value, sizeof(db->accreg_db)); + else + return false;// not found + return true; + } + + return false;// not found } /// create a new account entry /// If acc->account_id is -1, the account id will be auto-generated, /// and its value will be written to acc->account_id if everything succeeds. -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc) +static bool account_db_sql_create(AccountDB *self, struct mmo_account *acc) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - - // decide on the account id to assign - int account_id; - if( acc->account_id != -1 ) - {// caller specifies it manually - account_id = acc->account_id; - } - else - {// ask the database - char* data; - size_t len; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, &len); - account_id = ( data != NULL ) ? atoi(data) : 0; - Sql_FreeResult(sql_handle); - - if( account_id < START_ACCOUNT_NUM ) - account_id = START_ACCOUNT_NUM; - - } - - // zero value is prohibited - if( account_id == 0 ) - return false; - - // absolute maximum - if( account_id > END_ACCOUNT_NUM ) - return false; - - // insert the data into the database - acc->account_id = account_id; - return mmo_auth_tosql(db, acc, true); + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + + // decide on the account id to assign + int account_id; + if (acc->account_id != -1) { + // caller specifies it manually + account_id = acc->account_id; + } else { + // ask the database + char *data; + size_t len; + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db)) { + Sql_ShowDebug(sql_handle); + return false; + } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, &len); + account_id = (data != NULL) ? atoi(data) : 0; + Sql_FreeResult(sql_handle); + + if (account_id < START_ACCOUNT_NUM) + account_id = START_ACCOUNT_NUM; + + } + + // zero value is prohibited + if (account_id == 0) + return false; + + // absolute maximum + if (account_id > END_ACCOUNT_NUM) + return false; + + // insert the data into the database + acc->account_id = account_id; + return mmo_auth_tosql(db, acc, true); } /// delete an existing account entry + its regs -static bool account_db_sql_remove(AccountDB* self, const int account_id) +static bool account_db_sql_remove(AccountDB *self, const int account_id) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - bool result = false; + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + bool result = false; - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) ) - Sql_ShowDebug(sql_handle); - else - result = true; + if (SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") + || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) + || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id)) + Sql_ShowDebug(sql_handle); + else + result = true; - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); + result &= (SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK")); - return result; + return result; } /// update an existing account with the provided new data (both account and regs) -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc) +static bool account_db_sql_save(AccountDB *self, const struct mmo_account *acc) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_tosql(db, acc, false); + AccountDB_SQL *db = (AccountDB_SQL *)self; + return mmo_auth_tosql(db, acc, false); } /// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id) +static bool account_db_sql_load_num(AccountDB *self, struct mmo_account *acc, const int account_id) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_fromsql(db, acc, account_id); + AccountDB_SQL *db = (AccountDB_SQL *)self; + return mmo_auth_fromsql(db, acc, account_id); } /// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid) +static bool account_db_sql_load_str(AccountDB *self, struct mmo_account *acc, const char *userid) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - char esc_userid[2*NAME_LENGTH+1]; - int account_id; - char* data; - - Sql_EscapeString(sql_handle, esc_userid, userid); - - // get the list of account IDs for this user ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'", - db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( Sql_NumRows(sql_handle) > 1 ) - {// serious problem - duplicit account - ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid); - Sql_FreeResult(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - - return account_db_sql_load_num(self, acc, account_id); + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + char esc_userid[2*NAME_LENGTH+1]; + int account_id; + char *data; + + Sql_EscapeString(sql_handle, esc_userid, userid); + + // get the list of account IDs for this user ID + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'", + db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (Sql_NumRows(sql_handle) > 1) { + // serious problem - duplicit account + ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid); + Sql_FreeResult(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // no such entry + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + + return account_db_sql_load_num(self, acc, account_id); } /// Returns a new forward iterator. -static AccountDBIterator* account_db_sql_iterator(AccountDB* self) +static AccountDBIterator *account_db_sql_iterator(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL)); + AccountDB_SQL *db = (AccountDB_SQL *)self; + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)aCalloc(1, sizeof(AccountDBIterator_SQL)); - // set up the vtable - iter->vtable.destroy = &account_db_sql_iter_destroy; - iter->vtable.next = &account_db_sql_iter_next; + // set up the vtable + iter->vtable.destroy = &account_db_sql_iter_destroy; + iter->vtable.next = &account_db_sql_iter_next; - // fill data - iter->db = db; - iter->last_account_id = -1; + // fill data + iter->db = db; + iter->last_account_id = -1; - return &iter->vtable; + return &iter->vtable; } /// Destroys this iterator, releasing all allocated memory (including itself). -static void account_db_sql_iter_destroy(AccountDBIterator* self) +static void account_db_sql_iter_destroy(AccountDBIterator *self) { - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - aFree(iter); + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)self; + aFree(iter); } /// Fetches the next account in the database. -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc) +static bool account_db_sql_iter_next(AccountDBIterator *self, struct mmo_account *acc) { - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - AccountDB_SQL* db = (AccountDB_SQL*)iter->db; - Sql* sql_handle = db->accounts; - int account_id; - char* data; - - // get next account ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1", - db->account_db, iter->last_account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) && - SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) && - data != NULL ) - {// get account data - account_id = atoi(data); - if( mmo_auth_fromsql(db, acc, account_id) ) - { - iter->last_account_id = account_id; - Sql_FreeResult(sql_handle); - return true; - } - } - Sql_FreeResult(sql_handle); - return false; + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)self; + AccountDB_SQL *db = (AccountDB_SQL *)iter->db; + Sql *sql_handle = db->accounts; + int account_id; + char *data; + + // get next account ID + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1", + db->account_db, iter->last_account_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle) && + SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) && + data != NULL) { + // get account data + account_id = atoi(data); + if (mmo_auth_fromsql(db, acc, account_id)) { + iter->last_account_id = account_id; + Sql_FreeResult(sql_handle); + return true; + } + } + Sql_FreeResult(sql_handle); + return false; } -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id) +static bool mmo_auth_fromsql(AccountDB_SQL *db, struct mmo_account *acc, int account_id) { - Sql* sql_handle = db->accounts; - char* data; - int i = 0; - - // retrieve login entry for the specified account - if( SQL_ERROR == Sql_Query(sql_handle, - "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", - db->account_db, account_id ) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); acc->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid)); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass)); - Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0]; - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email)); - Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data); - Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data); - Sql_GetData(sql_handle, 9, &data, NULL); acc->logincount = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin)); - Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip)); - Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate)); - - Sql_FreeResult(sql_handle); - - - // retrieve account regs for the specified user - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - acc->account_reg2_num = (int)Sql_NumRows(sql_handle); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str)); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value)); - ++i; - } - Sql_FreeResult(sql_handle); - - if( i != acc->account_reg2_num ) - return false; - - return true; + Sql *sql_handle = db->accounts; + char *data; + int i = 0; + + // retrieve login entry for the specified account + if (SQL_ERROR == Sql_Query(sql_handle, + "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", + db->account_db, account_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // no such entry + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + acc->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(acc->userid, data, sizeof(acc->userid)); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(acc->pass, data, sizeof(acc->pass)); + Sql_GetData(sql_handle, 3, &data, NULL); + acc->sex = data[0]; + Sql_GetData(sql_handle, 4, &data, NULL); + safestrncpy(acc->email, data, sizeof(acc->email)); + Sql_GetData(sql_handle, 5, &data, NULL); + acc->group_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + acc->state = strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); + acc->unban_time = atol(data); + Sql_GetData(sql_handle, 8, &data, NULL); + acc->expiration_time = atol(data); + Sql_GetData(sql_handle, 9, &data, NULL); + acc->logincount = strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 10, &data, NULL); + safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin)); + Sql_GetData(sql_handle, 11, &data, NULL); + safestrncpy(acc->last_ip, data, sizeof(acc->last_ip)); + Sql_GetData(sql_handle, 12, &data, NULL); + safestrncpy(acc->birthdate, data, sizeof(acc->birthdate)); + + Sql_FreeResult(sql_handle); + + + // retrieve account regs for the specified user + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + acc->account_reg2_num = (int)Sql_NumRows(sql_handle); + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str)); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value)); + ++i; + } + Sql_FreeResult(sql_handle); + + if (i != acc->account_reg2_num) + return false; + + return true; } -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new) +static bool mmo_auth_tosql(AccountDB_SQL *db, const struct mmo_account *acc, bool is_new) { - Sql* sql_handle = db->accounts; - SqlStmt* stmt = SqlStmt_Malloc(sql_handle); - bool result = false; - int i; - - // try - do - { - - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") ) - { - Sql_ShowDebug(sql_handle); - break; - } - - if( is_new ) - {// insert into account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, - "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - db->account_db) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - else - {// update account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - - // remove old account regs - if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - break; - } - // insert new account regs - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) ) - { - SqlStmt_ShowDebug(stmt); - break; - } - for( i = 0; i < acc->account_reg2_num; ++i ) - { - if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - if( i < acc->account_reg2_num ) - { - result = false; - break; - } - - // if we got this far, everything was successful - result = true; - - } while(0); - // finally - - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); - SqlStmt_Free(stmt); - - return result; + Sql *sql_handle = db->accounts; + SqlStmt *stmt = SqlStmt_Malloc(sql_handle); + bool result = false; + int i; + + // try + do { + + if (SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION")) { + Sql_ShowDebug(sql_handle); + break; + } + + if (is_new) { + // insert into account table + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, + "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + db->account_db) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void *)&acc->account_id, sizeof(acc->account_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void *)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void *)&acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void *)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void *)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void *)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void *)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void *)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void *)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void *)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void *)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } else { + // update account table + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void *)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void *)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void *)acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void *)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void *)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void *)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void *)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void *)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void *)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void *)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void *)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } + + // remove old account regs + if (SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id)) { + Sql_ShowDebug(sql_handle); + break; + } + // insert new account regs + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id)) { + SqlStmt_ShowDebug(stmt); + break; + } + for (i = 0; i < acc->account_reg2_num; ++i) { + if (SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void *)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } + if (i < acc->account_reg2_num) { + result = false; + break; + } + + // if we got this far, everything was successful + result = true; + + } while (0); + // finally + + result &= (SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK")); + SqlStmt_Free(stmt); + + return result; } diff --git a/src/login/ipban.h b/src/login/ipban.h index b2a1a7d9e..6adc40483 100644 --- a/src/login/ipban.h +++ b/src/login/ipban.h @@ -19,7 +19,7 @@ bool ipban_check(uint32 ip); void ipban_log(uint32 ip); // parses configuration option -bool ipban_config_read(const char* key, const char* value); +bool ipban_config_read(const char *key, const char *value); #endif // __IPBAN_H_INCLUDED__ diff --git a/src/login/ipban_sql.c b/src/login/ipban_sql.c index c75a1f956..eec9a98be 100644 --- a/src/login/ipban_sql.c +++ b/src/login/ipban_sql.c @@ -31,7 +31,7 @@ static char ipban_codepage[32] = ""; static char ipban_table[32] = "ipbanlist"; // globals -static Sql* sql_handle = NULL; +static Sql *sql_handle = NULL; static int cleanup_timer_id = INVALID_TIMER; static bool ipban_inited = false; @@ -41,218 +41,196 @@ int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data); // initialize void ipban_init(void) { - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - ipban_inited = true; - - if( !login_config.ipban ) - return;// ipban disabled - - if( ipban_db_hostname[0] != '\0' ) - {// local settings - username = ipban_db_username; - password = ipban_db_password; - hostname = ipban_db_hostname; - port = ipban_db_port; - database = ipban_db_database; - codepage = ipban_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - // establish connections - sql_handle = Sql_Malloc(); - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - if( login_config.ipban_cleanup_interval > 0 ) - { // set up periodic cleanup of connection history and active bans - add_timer_func_list(ipban_cleanup, "ipban_cleanup"); - cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); - } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups - ipban_cleanup(0,0,0,0); + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + ipban_inited = true; + + if (!login_config.ipban) + return;// ipban disabled + + if (ipban_db_hostname[0] != '\0') { + // local settings + username = ipban_db_username; + password = ipban_db_password; + hostname = ipban_db_hostname; + port = ipban_db_port; + database = ipban_db_database; + codepage = ipban_codepage; + } else { + // global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + // establish connections + sql_handle = Sql_Malloc(); + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + if (login_config.ipban_cleanup_interval > 0) { + // set up periodic cleanup of connection history and active bans + add_timer_func_list(ipban_cleanup, "ipban_cleanup"); + cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); + } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups + ipban_cleanup(0,0,0,0); } // finalize void ipban_final(void) { - if( !login_config.ipban ) - return;// ipban disabled - - if( login_config.ipban_cleanup_interval > 0 ) - // release data - delete_timer(cleanup_timer_id, ipban_cleanup); - - ipban_cleanup(0,0,0,0); // always clean up on login-server stop - - // close connections - Sql_Free(sql_handle); - sql_handle = NULL; + if (!login_config.ipban) + return;// ipban disabled + + if (login_config.ipban_cleanup_interval > 0) + // release data + delete_timer(cleanup_timer_id, ipban_cleanup); + + ipban_cleanup(0,0,0,0); // always clean up on login-server stop + + // close connections + Sql_Free(sql_handle); + sql_handle = NULL; } // load configuration options -bool ipban_config_read(const char* key, const char* value) +bool ipban_config_read(const char *key, const char *value) { - const char* signature; - - if( ipban_inited ) - return false;// settings can only be changed before init - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - signature = "ipban.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - ipban_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); - else - if( strcmpi(key, "ipban_table") == 0 ) - safestrncpy(ipban_table, value, sizeof(ipban_table)); - else - return false;// not found - return true; - } - - signature = "ipban."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "enable") == 0 ) - login_config.ipban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban") == 0 ) - login_config.dynamic_pass_failure_ban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 ) - login_config.dynamic_pass_failure_ban_interval = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 ) - login_config.dynamic_pass_failure_ban_limit = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 ) - login_config.dynamic_pass_failure_ban_duration = atoi(value); - else - return false;// not found - return true; - } - - return false;// not found + const char *signature; + + if (ipban_inited) + return false;// settings can only be changed before init + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + signature = "ipban.sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + ipban_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); + else if (strcmpi(key, "ipban_table") == 0) + safestrncpy(ipban_table, value, sizeof(ipban_table)); + else + return false;// not found + return true; + } + + signature = "ipban."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "enable") == 0) + login_config.ipban = (bool)config_switch(value); + else if (strcmpi(key, "dynamic_pass_failure_ban") == 0) + login_config.dynamic_pass_failure_ban = (bool)config_switch(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_interval") == 0) + login_config.dynamic_pass_failure_ban_interval = atoi(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_limit") == 0) + login_config.dynamic_pass_failure_ban_limit = atoi(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_duration") == 0) + login_config.dynamic_pass_failure_ban_duration = atoi(value); + else + return false;// not found + return true; + } + + return false;// not found } // check ip against active bans list bool ipban_check(uint32 ip) { - uint8* p = (uint8*)&ip; - char* data = NULL; - int matches; + uint8 *p = (uint8 *)&ip; + char *data = NULL; + int matches; - if( !login_config.ipban ) - return false;// ipban disabled + if (!login_config.ipban) + return false;// ipban disabled - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", - ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) ) - { - Sql_ShowDebug(sql_handle); - // close connection because we can't verify their connectivity. - return true; - } + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", + ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0])) { + Sql_ShowDebug(sql_handle); + // close connection because we can't verify their connectivity. + return true; + } - if( SQL_ERROR == Sql_NextRow(sql_handle) ) - return true;// Shouldn't happen, but just in case... + if (SQL_ERROR == Sql_NextRow(sql_handle)) + return true;// Shouldn't happen, but just in case... - Sql_GetData(sql_handle, 0, &data, NULL); - matches = atoi(data); - Sql_FreeResult(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + matches = atoi(data); + Sql_FreeResult(sql_handle); - return( matches > 0 ); + return(matches > 0); } // log failed attempt void ipban_log(uint32 ip) { - unsigned long failures; + unsigned long failures; - if( !login_config.ipban ) - return;// ipban disabled + if (!login_config.ipban) + return;// ipban disabled - failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. + failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. - // if over the limit, add a temporary ban entry - if( failures >= login_config.dynamic_pass_failure_ban_limit ) - { - uint8* p = (uint8*)&ip; - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", - ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) ) - Sql_ShowDebug(sql_handle); - } + // if over the limit, add a temporary ban entry + if (failures >= login_config.dynamic_pass_failure_ban_limit) { + uint8 *p = (uint8 *)&ip; + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", + ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration)) + Sql_ShowDebug(sql_handle); + } } // remove expired bans int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - if( !login_config.ipban ) - return 0;// ipban disabled + if (!login_config.ipban) + return 0;// ipban disabled - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()") ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()")) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } diff --git a/src/login/login.c b/src/login/login.c index e079dbaf2..1f63463d5 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -25,31 +25,31 @@ int login_fd; // login server socket struct mmo_char_server server[MAX_SERVERS]; // char server data // Account engines available -static struct{ - AccountDB* (*constructor)(void); - AccountDB* db; +static struct { + AccountDB *(*constructor)(void); + AccountDB *db; } account_engines[] = { - {account_db_sql, NULL}, + {account_db_sql, NULL}, #ifdef ACCOUNTDB_ENGINE_0 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_1 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_2 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_3 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_4 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, #endif - // end of structure - {NULL, NULL} + // end of structure + {NULL, NULL} }; // account database -AccountDB* accounts = NULL; +AccountDB *accounts = NULL; //Account registration flood protection [Kevin] int allowed_regs = 1; @@ -57,14 +57,14 @@ int time_allowed = 10; //in seconds // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip); +int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip); //----------------------------------------------------- // Auth database @@ -73,16 +73,16 @@ int mmo_auth_new(const char* userid, const char* pass, const char sex, const cha struct auth_node { - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; - uint32 version; - uint8 clienttype; + int account_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + char sex; + uint32 version; + uint8 clienttype; }; -static DBMap* auth_db; // int account_id -> struct auth_node* +static DBMap *auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- @@ -90,12 +90,12 @@ static DBMap* auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- struct online_login_data { - int account_id; - int waiting_disconnect; - int char_server; + int account_id; + int waiting_disconnect; + int char_server; }; -static DBMap* online_db; // int account_id -> struct online_login_data* +static DBMap *online_db; // int account_id -> struct online_login_data* static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data); /** @@ -103,49 +103,46 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static DBData create_online_user(DBKey key, va_list args) { - struct online_login_data* p; - CREATE(p, struct online_login_data, 1); - p->account_id = key.i; - p->char_server = -1; - p->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(p); + struct online_login_data *p; + CREATE(p, struct online_login_data, 1); + p->account_id = key.i; + p->char_server = -1; + p->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(p); } -struct online_login_data* add_online_user(int char_server, int account_id) -{ - struct online_login_data* p; - p = idb_ensure(online_db, account_id, create_online_user); - p->char_server = char_server; - if( p->waiting_disconnect != INVALID_TIMER ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - return p; +struct online_login_data *add_online_user(int char_server, int account_id) { + struct online_login_data *p; + p = idb_ensure(online_db, account_id, create_online_user); + p->char_server = char_server; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + return p; } void remove_online_user(int account_id) { - struct online_login_data* p; - p = (struct online_login_data*)idb_get(online_db, account_id); - if( p == NULL ) - return; - if( p->waiting_disconnect != INVALID_TIMER ) - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - - idb_remove(online_db, account_id); + struct online_login_data *p; + p = (struct online_login_data *)idb_get(online_db, account_id); + if (p == NULL) + return; + if (p->waiting_disconnect != INVALID_TIMER) + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + + idb_remove(online_db, account_id); } static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); - if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) - { - p->waiting_disconnect = INVALID_TIMER; - remove_online_user(id); - idb_remove(auth_db, id); - } - return 0; + struct online_login_data *p = (struct online_login_data *)idb_get(online_db, id); + if (p != NULL && p->waiting_disconnect == tid && p->account_id == id) { + p->waiting_disconnect = INVALID_TIMER; + remove_online_user(id); + idb_remove(auth_db, id); + } + return 0; } /** @@ -153,20 +150,17 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_login_data* p = db_data2ptr(data); - int server = va_arg(ap, int); - if( server == -1 ) - { - p->char_server = -1; - if( p->waiting_disconnect != INVALID_TIMER ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } - else if( p->char_server == server ) - p->char_server = -2; //Char server disconnected. - return 0; + struct online_login_data *p = db_data2ptr(data); + int server = va_arg(ap, int); + if (server == -1) { + p->char_server = -1; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } else if (p->char_server == server) + p->char_server = -2; //Char server disconnected. + return 0; } /** @@ -174,75 +168,72 @@ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_login_data *character= db_data2ptr(data); - if (character->char_server == -2) //Unknown server.. set them offline - remove_online_user(character->account_id); - return 0; + struct online_login_data *character= db_data2ptr(data); + if (character->char_server == -2) //Unknown server.. set them offline + remove_online_user(character->account_id); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_db->foreach(online_db, online_data_cleanup_sub); - return 0; -} + online_db->foreach(online_db, online_data_cleanup_sub); + return 0; +} //-------------------------------------------------------------------- // Packet send to all char-servers, except one (wos: without our self) //-------------------------------------------------------------------- -int charif_sendallwos(int sfd, uint8* buf, size_t len) +int charif_sendallwos(int sfd, uint8 *buf, size_t len) { - int i, c; - - for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i ) - { - int fd = server[i].fd; - if( session_isValid(fd) && fd != sfd ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - ++c; - } - } - - return c; + int i, c; + + for (i = 0, c = 0; i < ARRAYLENGTH(server); ++i) { + int fd = server[i].fd; + if (session_isValid(fd) && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + ++c; + } + } + + return c; } /// Initializes a server structure. void chrif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void chrif_server_destroy(int id) { - if( server[id].fd != -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } + if (server[id].fd != -1) { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void chrif_server_reset(int id) { - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - chrif_server_destroy(id); - chrif_server_init(id); + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. + chrif_server_destroy(id); + chrif_server_init(id); } /// Called when the connection to Char Server is disconnected. void chrif_on_disconnect(int id) { - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - chrif_server_reset(id); + ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); + chrif_server_reset(id); } @@ -251,52 +242,49 @@ void chrif_on_disconnect(int id) //----------------------------------------------------- static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; + uint8 buf[2]; + ShowInfo("IP Sync in progress...\n"); + WBUFW(buf,0) = 0x2735; + charif_sendallwos(-1, buf, 2); + return 0; } //----------------------------------------------------- // encrypted/unencrypted password check (from eApp) //----------------------------------------------------- -bool check_encrypted(const char* str1, const char* str2, const char* passwd) +bool check_encrypted(const char *str1, const char *str2, const char *passwd) { - char tmpstr[64+1], md5str[32+1]; + char tmpstr[64+1], md5str[32+1]; - safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); - MD5_String(tmpstr, md5str); + safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); + MD5_String(tmpstr, md5str); - return (0==strcmp(passwd, md5str)); + return (0==strcmp(passwd, md5str)); } -bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) +bool check_password(const char *md5key, int passwdenc, const char *passwd, const char *refpass) { - if(passwdenc == 0) - { - return (0==strcmp(passwd, refpass)); - } - else - { - // password mode set to 1 -> md5(md5key, refpass) enable with - // password mode set to 2 -> md5(refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); - } + if (passwdenc == 0) { + return (0==strcmp(passwd, refpass)); + } else { + // password mode set to 1 -> md5(md5key, refpass) enable with + // password mode set to 2 -> md5(refpass, md5key) enable with + + return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || + ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); + } } //----------------------------------------------------- // custom timestamp formatting (from eApp) //----------------------------------------------------- -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) +const char *timestamp2string(char *str, size_t size, time_t timestamp, const char *format) { - size_t len = strftime(str, size, format, localtime(×tamp)); - memset(str + len, '\0', size - len); - return str; + size_t len = strftime(str, size, format, localtime(×tamp)); + memset(str + len, '\0', size - len); + return str; } @@ -305,9 +293,9 @@ const char* timestamp2string(char* str, size_t size, time_t timestamp, const cha //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - return ( i < subnet_count ) ? subnet[i].char_ip : 0; + int i; + ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); + return (i < subnet_count) ? subnet[i].char_ip : 0; } //---------------------------------- @@ -315,99 +303,89 @@ int lan_subnetcheck(uint32 ip) //---------------------------------- int login_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) - { - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if( subnet_count > 1 ) /* only useful if there is more than 1 available */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if ((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + if (strcmpi(w1, "subnet") == 0) { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if (subnet_count > 1) /* only useful if there is more than 1 available */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } //----------------------- // Console Command Parser [Wizputer] //----------------------- -int parse_console(const char* command) +int parse_console(const char *command) { - ShowNotice("Console command: %s\n", command); - - if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ) - { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - ShowInfo("To create a new account:\n"); - ShowInfo(" 'create'\n"); - } - else - {// commands with parameters - char cmd[128], params[256]; - - if( sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2 ) - { - return 0; - } - - if( strcmpi(cmd, "create") == 0 ) - { - char username[NAME_LENGTH], password[NAME_LENGTH], sex; - - if( sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ) - { - ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); - return 0; - } - - if( mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1 ) - { - ShowError("Console: Account creation failed.\n"); - return 0; - } - ShowStatus("Console: Account '%s' created successfully.\n", username); - } - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) + runflag = 0; + else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if (strcmpi("help", command) == 0) { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + ShowInfo("To create a new account:\n"); + ShowInfo(" 'create'\n"); + } else { + // commands with parameters + char cmd[128], params[256]; + + if (sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2) { + return 0; + } + + if (strcmpi(cmd, "create") == 0) { + char username[NAME_LENGTH], password[NAME_LENGTH], sex; + + if (sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1) { + ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); + return 0; + } + + if (mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1) { + ShowError("Console: Account creation failed.\n"); + return 0; + } + ShowStatus("Console: Account '%s' created successfully.\n", username); + } + } + + return 0; } @@ -416,880 +394,898 @@ int parse_console(const char* command) //-------------------------------- int parse_fromchar(int fd) { - int j, id; - uint32 ipl; - char ip[16]; - - ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); - if( id == ARRAYLENGTH(server) ) - {// not a char server - ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); - set_eof(fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) - { - do_close(fd); - server[id].fd = -1; - chrif_on_disconnect(id); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x2712: // request from char-server to authenticate an account - if( RFIFOREST(fd) < 23 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - //uint32 ip_ = ntohl(RFIFOL(fd,15)); - int request_id = RFIFOL(fd,19); - RFIFOSKIP(fd,23); - - node = (struct auth_node*)idb_get(auth_db, account_id); - if( runflag == LOGINSERVER_ST_RUNNING && - node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 && - node->sex == sex_num2str(sex) /*&& - node->ip == ip_*/ ) - {// found - //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); - - // send ack - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 0;// ok - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = node->version; - WFIFOB(fd,24) = node->clienttype; - WFIFOSET(fd,25); - - // each auth entry can only be used once - idb_remove(auth_db, account_id); - } - else - {// authentication not found - ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 1;// auth failed - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = 0; - WFIFOB(fd,24) = 0; - WFIFOSET(fd,25); - } - } - break; - - case 0x2714: - if( RFIFOREST(fd) < 6 ) - return 0; - { - int users = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - // how many users on world? (update) - if( server[id].users != users ) - { - ShowStatus("set users %s : %d\n", server[id].name, users); - - server[id].users = users; - } - } - break; - - case 0x2715: // request from char server to change e-email from default "a@a.com" - if (RFIFOREST(fd) < 46) - return 0; - { - struct mmo_account acc; - char email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); - RFIFOSKIP(fd,46); - - if( e_mail_check(email) == 0 ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0' ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else { - memcpy(acc.email, email, 40); - ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2716: // request account data - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - time_t expiration_time = 0; - char email[40] = ""; - int group_id = 0; - char birthdate[10+1] = ""; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); - else - { - safestrncpy(email, acc.email, sizeof(email)); - expiration_time = acc.expiration_time; - group_id = acc.group_id; - safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); - } - - WFIFOHEAD(fd,62); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = account_id; - safestrncpy((char*)WFIFOP(fd,6), email, 40); - WFIFOL(fd,46) = (uint32)expiration_time; - WFIFOB(fd,50) = group_id; - safestrncpy((char*)WFIFOP(fd,51), birthdate, 10+1); - WFIFOSET(fd,62); - } - break; - - case 0x2719: // ping request from charserver - RFIFOSKIP(fd,2); - - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2718; - WFIFOSET(fd,2); - break; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST(fd) < 86) - return 0; - { - struct mmo_account acc; - char actual_email[40]; - char new_email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); - safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); - RFIFOSKIP(fd, 86); - - if( e_mail_check(actual_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( e_mail_check(new_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( strcmpi(new_email, "a@a.com") == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - if( strcmpi(acc.email, actual_email) != 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); - else { - safestrncpy(acc.email, new_email, 40); - ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - unsigned int state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else - if( acc.state == state ) - ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else { - ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); - - acc.state = state; - // Save - accounts->save(accounts, &acc); - - // notify other servers - if (state != 0) { - uint8 buf[11]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 0; // 0: change of state, 1: ban - WBUFL(buf,7) = state; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - int year = (short)RFIFOW(fd,6); - int month = (short)RFIFOW(fd,8); - int mday = (short)RFIFOW(fd,10); - int hour = (short)RFIFOW(fd,12); - int min = (short)RFIFOW(fd,14); - int sec = (short)RFIFOW(fd,16); - RFIFOSKIP(fd,18); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - { - time_t timestamp; - struct tm *tmtime; - if (acc.unban_time == 0 || acc.unban_time < time(NULL)) - timestamp = time(NULL); // new ban - else - timestamp = acc.unban_time; // add to existing ban - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + year; - tmtime->tm_mon = tmtime->tm_mon + month; - tmtime->tm_mday = tmtime->tm_mday + mday; - tmtime->tm_hour = tmtime->tm_hour + hour; - tmtime->tm_min = tmtime->tm_min + min; - tmtime->tm_sec = tmtime->tm_sec + sec; - timestamp = mktime(tmtime); - if (timestamp == -1) - ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); - else - if( timestamp <= time(NULL) || timestamp == 0 ) - ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); - else - { - uint8 buf[11]; - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); - ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); - - acc.unban_time = timestamp; - - // Save - accounts->save(accounts, &acc); - - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 1; // 0: change of status, 1: ban - WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2727: // Change of sex (sex is reversed) - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( acc.sex == 'S' ) - ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - { - unsigned char buf[7]; - char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender - - ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); - - acc.sex = sex; - // Save - accounts->save(accounts, &acc); - - // announce to other servers - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = sex_str2num(sex); - charif_sendallwos(-1, buf, 7); - } - } - break; - - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. - if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,4); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - { - int len; - int p; - ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); - for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ) - { - sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); - acc.account_reg2[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); - acc.account_reg2[j].value[len]='\0'; - p +=len+1; - remove_control_chars(acc.account_reg2[j].str); - remove_control_chars(acc.account_reg2[j].value); - } - acc.account_reg2_num = j; - - // Save - accounts->save(accounts, &acc); - - // Sending information towards the other char-servers. - RFIFOW(fd,0) = 0x2729;// reusing read buffer - charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x272a: // Receiving of map-server via char-server an unban request - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( acc.unban_time == 0 ) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); - else - { - ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); - acc.unban_time = 0; - accounts->save(accounts, &acc); - } - } - break; - - case 0x272b: // Set account_id to online [Wizputer] - if( RFIFOREST(fd) < 6 ) - return 0; - add_online_user(id, RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272c: // Set account_id to offline [Wizputer] - if( RFIFOREST(fd) < 6 ) - return 0; - remove_online_user(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272d: // Receive list of all online accounts. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - struct online_login_data *p; - int aid; - uint32 i, users; - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first - users = RFIFOW(fd,4); - for (i = 0; i < users; i++) { - aid = RFIFOL(fd,6+i*4); - p = idb_ensure(online_db, aid, create_online_user); - p->char_server = id; - if (p->waiting_disconnect != INVALID_TIMER) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - size_t off; - - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); - WFIFOW(fd,0) = 0x2729; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 1; //Type 1 for Account2 registry - - off = 13; - if( accounts->load_num(accounts, &acc, account_id) ) - { - for( j = 0; j < acc.account_reg2_num; j++ ) - { - if( acc.account_reg2[j].str[0] != '\0' ) - { - off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. - off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; - } - } - } - - WFIFOW(fd,2) = (uint16)off; - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2736: // WAN IP update from char-server - if( RFIFOREST(fd) < 6 ) - return 0; - server[id].ip = ntohl(RFIFOL(fd,2)); - ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x2737: //Request to set all offline. - ShowInfo("Setting accounts from char-server %d offline.\n", id); - online_db->foreach(online_db, online_db_setoffline, id); - RFIFOSKIP(fd,2); - break; - - default: - ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); - set_eof(fd); - return 0; - } // switch - } // while - - return 0; + int j, id; + uint32 ipl; + char ip[16]; + + ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); + if (id == ARRAYLENGTH(server)) { + // not a char server + ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); + set_eof(fd); + do_close(fd); + return 0; + } + + if (session[fd]->flag.eof) { + do_close(fd); + server[id].fd = -1; + chrif_on_disconnect(id); + return 0; + } + + ipl = server[id].ip; + ip2str(ipl, ip); + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + case 0x2712: // request from char-server to authenticate an account + if (RFIFOREST(fd) < 23) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + //uint32 ip_ = ntohl(RFIFOL(fd,15)); + int request_id = RFIFOL(fd,19); + RFIFOSKIP(fd,23); + + node = (struct auth_node *)idb_get(auth_db, account_id); + if (runflag == LOGINSERVER_ST_RUNNING && + node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->sex == sex_num2str(sex) /*&& + node->ip == ip_*/) { + // found + //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); + + // send ack + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 0;// ok + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = node->version; + WFIFOB(fd,24) = node->clienttype; + WFIFOSET(fd,25); + + // each auth entry can only be used once + idb_remove(auth_db, account_id); + } else { + // authentication not found + ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 1;// auth failed + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = 0; + WFIFOB(fd,24) = 0; + WFIFOSET(fd,25); + } + } + break; + + case 0x2714: + if (RFIFOREST(fd) < 6) + return 0; + { + int users = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + // how many users on world? (update) + if (server[id].users != users) { + ShowStatus("set users %s : %d\n", server[id].name, users); + + server[id].users = users; + } + } + break; + + case 0x2715: // request from char server to change e-email from default "a@a.com" + if (RFIFOREST(fd) < 46) + return 0; + { + struct mmo_account acc; + char email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(email, (char *)RFIFOP(fd,6), 40); + remove_control_chars(email); + RFIFOSKIP(fd,46); + + if (e_mail_check(email) == 0) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (!accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0') + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else { + memcpy(acc.email, email, 40); + ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2716: // request account data + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + time_t expiration_time = 0; + char email[40] = ""; + int group_id = 0; + char birthdate[10+1] = ""; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); + else { + safestrncpy(email, acc.email, sizeof(email)); + expiration_time = acc.expiration_time; + group_id = acc.group_id; + safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); + } + + WFIFOHEAD(fd,62); + WFIFOW(fd,0) = 0x2717; + WFIFOL(fd,2) = account_id; + safestrncpy((char *)WFIFOP(fd,6), email, 40); + WFIFOL(fd,46) = (uint32)expiration_time; + WFIFOB(fd,50) = group_id; + safestrncpy((char *)WFIFOP(fd,51), birthdate, 10+1); + WFIFOSET(fd,62); + } + break; + + case 0x2719: // ping request from charserver + RFIFOSKIP(fd,2); + + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2718; + WFIFOSET(fd,2); + break; + + // Map server send information to change an email of an account via char-server + case 0x2722: // 0x2722 .L .40B .40B + if (RFIFOREST(fd) < 86) + return 0; + { + struct mmo_account acc; + char actual_email[40]; + char new_email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(actual_email, (char *)RFIFOP(fd,6), 40); + safestrncpy(new_email, (char *)RFIFOP(fd,46), 40); + RFIFOSKIP(fd, 86); + + if (e_mail_check(actual_email) == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (e_mail_check(new_email) == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (strcmpi(new_email, "a@a.com") == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else if (strcmpi(acc.email, actual_email) != 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); + else { + safestrncpy(acc.email, new_email, 40); + ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + unsigned int state = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else if (acc.state == state) + ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else { + ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); + + acc.state = state; + // Save + accounts->save(accounts, &acc); + + // notify other servers + if (state != 0) { + uint8 buf[11]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 0; // 0: change of state, 1: ban + WBUFL(buf,7) = state; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2725: // Receiving of map-server via char-server a ban request + if (RFIFOREST(fd) < 18) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + int year = (short)RFIFOW(fd,6); + int month = (short)RFIFOW(fd,8); + int mday = (short)RFIFOW(fd,10); + int hour = (short)RFIFOW(fd,12); + int min = (short)RFIFOW(fd,14); + int sec = (short)RFIFOW(fd,16); + RFIFOSKIP(fd,18); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else { + time_t timestamp; + struct tm *tmtime; + if (acc.unban_time == 0 || acc.unban_time < time(NULL)) + timestamp = time(NULL); // new ban + else + timestamp = acc.unban_time; // add to existing ban + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + mday; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + min; + tmtime->tm_sec = tmtime->tm_sec + sec; + timestamp = mktime(tmtime); + if (timestamp == -1) + ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); + else if (timestamp <= time(NULL) || timestamp == 0) + ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); + else { + uint8 buf[11]; + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); + ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); + + acc.unban_time = timestamp; + + // Save + accounts->save(accounts, &acc); + + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 1; // 0: change of status, 1: ban + WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2727: // Change of sex (sex is reversed) + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else if (acc.sex == 'S') + ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else { + unsigned char buf[7]; + char sex = (acc.sex == 'M') ? 'F' : 'M'; //Change gender + + ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); + + acc.sex = sex; + // Save + accounts->save(accounts, &acc); + + // announce to other servers + WBUFW(buf,0) = 0x2723; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = sex_str2num(sex); + charif_sendallwos(-1, buf, 7); + } + } + break; + + case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,4); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else { + int len; + int p; + ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); + for (j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j) { + sscanf((char *)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); + acc.account_reg2[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char *)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); + acc.account_reg2[j].value[len]='\0'; + p +=len+1; + remove_control_chars(acc.account_reg2[j].str); + remove_control_chars(acc.account_reg2[j].value); + } + acc.account_reg2_num = j; + + // Save + accounts->save(accounts, &acc); + + // Sending information towards the other char-servers. + RFIFOW(fd,0) = 0x2729;// reusing read buffer + charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x272a: // Receiving of map-server via char-server an unban request + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else if (acc.unban_time == 0) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); + else { + ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); + acc.unban_time = 0; + accounts->save(accounts, &acc); + } + } + break; + + case 0x272b: // Set account_id to online [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + add_online_user(id, RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272c: // Set account_id to offline [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + remove_online_user(RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272d: // Receive list of all online accounts. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + struct online_login_data *p; + int aid; + uint32 i, users; + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first + users = RFIFOW(fd,4); + for (i = 0; i < users; i++) { + aid = RFIFOL(fd,6+i*4); + p = idb_ensure(online_db, aid, create_online_user); + p->char_server = id; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x272e: //Request account_reg2 for a character. + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + size_t off; + + int account_id = RFIFOL(fd,2); + int char_id = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); + WFIFOW(fd,0) = 0x2729; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = char_id; + WFIFOB(fd,12) = 1; //Type 1 for Account2 registry + + off = 13; + if (accounts->load_num(accounts, &acc, account_id)) { + for (j = 0; j < acc.account_reg2_num; j++) { + if (acc.account_reg2[j].str[0] != '\0') { + off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. + off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; + } + } + } + + WFIFOW(fd,2) = (uint16)off; + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2736: // WAN IP update from char-server + if (RFIFOREST(fd) < 6) + return 0; + server[id].ip = ntohl(RFIFOL(fd,2)); + ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x2737: //Request to set all offline. + ShowInfo("Setting accounts from char-server %d offline.\n", id); + online_db->foreach(online_db, online_db_setoffline, id); + RFIFOSKIP(fd,2); + break; + + default: + ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); + set_eof(fd); + return 0; + } // switch + } // while + + return 0; } //------------------------------------- // Make new account //------------------------------------- -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip) { - static int num_regs = 0; // registration counter - static unsigned int new_reg_tick = 0; - unsigned int tick = gettick(); - struct mmo_account acc; - - //Account Registration Flood Protection by [Kevin] - if( new_reg_tick == 0 ) - new_reg_tick = gettick(); - if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) { - ShowNotice("Account registration denied (registration limit exceeded)\n"); - return 3; - } - - if( login_config.new_acc_length_limit && ( strlen(userid) < 4 || strlen(pass) < 4 ) ) - return 1; - - // check for invalid inputs - if( sex != 'M' && sex != 'F' ) - return 0; // 0 = Unregistered ID - - // check if the account doesn't exist already - if( accounts->load_str(accounts, &acc, userid) ) { - ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); - return 1; // 1 = Incorrect Password - } - - memset(&acc, '\0', sizeof(acc)); - acc.account_id = -1; // assigned by account db - safestrncpy(acc.userid, userid, sizeof(acc.userid)); - safestrncpy(acc.pass, pass, sizeof(acc.pass)); - acc.sex = sex; - safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); - acc.expiration_time = ( login_config.start_limited_time != -1 ) ? time(NULL) + login_config.start_limited_time : 0; - safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); - safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); - safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); - - if( !accounts->create(accounts, &acc) ) - return 0; - - ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); - - if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check. - num_regs = 0; - new_reg_tick = tick + time_allowed*1000; - } - ++num_regs; - - return -1; +int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip) +{ + static int num_regs = 0; // registration counter + static unsigned int new_reg_tick = 0; + unsigned int tick = gettick(); + struct mmo_account acc; + + //Account Registration Flood Protection by [Kevin] + if (new_reg_tick == 0) + new_reg_tick = gettick(); + if (DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs) { + ShowNotice("Account registration denied (registration limit exceeded)\n"); + return 3; + } + + if (login_config.new_acc_length_limit && (strlen(userid) < 4 || strlen(pass) < 4)) + return 1; + + // check for invalid inputs + if (sex != 'M' && sex != 'F') + return 0; // 0 = Unregistered ID + + // check if the account doesn't exist already + if (accounts->load_str(accounts, &acc, userid)) { + ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); + return 1; // 1 = Incorrect Password + } + + memset(&acc, '\0', sizeof(acc)); + acc.account_id = -1; // assigned by account db + safestrncpy(acc.userid, userid, sizeof(acc.userid)); + safestrncpy(acc.pass, pass, sizeof(acc.pass)); + acc.sex = sex; + safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); + acc.expiration_time = (login_config.start_limited_time != -1) ? time(NULL) + login_config.start_limited_time : 0; + safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); + safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); + safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); + + if (!accounts->create(accounts, &acc)) + return 0; + + ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); + + if (DIFF_TICK(tick, new_reg_tick) > 0) { // Update the registration check. + num_regs = 0; + new_reg_tick = tick + time_allowed*1000; + } + ++num_regs; + + return -1; } //----------------------------------------------------- // Check/authentication of a connection //----------------------------------------------------- -int mmo_auth(struct login_session_data* sd, bool isServer) { - struct mmo_account acc; - int len; - - char ip[16]; - ip2str(session[sd->fd]->client_addr, ip); - - // DNS Blacklist check - if( login_config.use_dnsbl ) { - char r_ip[16]; - char ip_dnsbl[256]; - char* dnsbl_serv; - uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; - - sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - - for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) { - sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); - if( host2ip(ip_dnsbl) ) { - ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); - return 3; - } - } - - } - - //Client Version check - if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) - return 5; - - len = strnlen(sd->userid, NAME_LENGTH); - - // Account creation with _M/_F - if( login_config.new_account_flag ) { - if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths - sd->passwdenc == 0 && // unencoded password - sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix - { - int result; - - // remove the _M/_F suffix - len -= 2; - sd->userid[len] = '\0'; - - result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); - if( result != -1 ) - return result;// Failed to make account. [Skotlex]. - } - } - - if( !accounts->load_str(accounts, &acc, sd->userid) ) { - ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); - return 0; // 0 = Unregistered ID - } - - if( !check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) { - ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); - return 1; // 1 = Incorrect Password - } - - if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) { - ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); - return 2; // 2 = This ID is expired - } - - if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) { - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); - ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); - return 6; // 6 = Your are Prohibited to log in until %s - } - - if( acc.state != 0 ) { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return acc.state - 1; - } - - if( login_config.client_hash_check && !isServer ) { - struct client_hash_node *node = login_config.client_hash_nodes; - bool match = false; - - if( !sd->has_client_hash ) { - ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return 5; - } - - while( node ) { - if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) { - match = true; - break; - } - - node = node->next; - } - - if( !match ) { - char smd5[33]; - int i; - - for( i = 0; i < 16; i++ ) - sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); - - ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); - return 5; - } - } - - ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); - - // update session data - sd->account_id = acc.account_id; - sd->login_id1 = rnd(); - sd->login_id2 = rnd(); - safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); - sd->sex = acc.sex; - sd->group_id = acc.group_id; - - // update account data - timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); - safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); - acc.unban_time = 0; - acc.logincount++; - - accounts->save(accounts, &acc); - - if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) - ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); - - return -1; // account OK +int mmo_auth(struct login_session_data *sd, bool isServer) +{ + struct mmo_account acc; + int len; + + char ip[16]; + ip2str(session[sd->fd]->client_addr, ip); + + // DNS Blacklist check + if (login_config.use_dnsbl) { + char r_ip[16]; + char ip_dnsbl[256]; + char *dnsbl_serv; + uint8 *sin_addr = (uint8 *)&session[sd->fd]->client_addr; + + sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); + + for (dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",")) { + sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); + if (host2ip(ip_dnsbl)) { + ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); + return 3; + } + } + + } + + //Client Version check + if (login_config.check_client_version && sd->version != login_config.client_version_to_connect) + return 5; + + len = strnlen(sd->userid, NAME_LENGTH); + + // Account creation with _M/_F + if (login_config.new_account_flag) { + if (len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths + sd->passwdenc == 0 && // unencoded password + sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4)) { // _M/_F suffix + int result; + + // remove the _M/_F suffix + len -= 2; + sd->userid[len] = '\0'; + + result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); + if (result != -1) + return result;// Failed to make account. [Skotlex]. + } + } + + if (!accounts->load_str(accounts, &acc, sd->userid)) { + ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); + return 0; // 0 = Unregistered ID + } + + if (!check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass)) { + ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); + return 1; // 1 = Incorrect Password + } + + if (acc.expiration_time != 0 && acc.expiration_time < time(NULL)) { + ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); + return 2; // 2 = This ID is expired + } + + if (acc.unban_time != 0 && acc.unban_time > time(NULL)) { + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); + ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); + return 6; // 6 = Your are Prohibited to log in until %s + } + + if (acc.state != 0) { + ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return acc.state - 1; + } + + if (login_config.client_hash_check && !isServer) { + struct client_hash_node *node = login_config.client_hash_nodes; + bool match = false; + + if (!sd->has_client_hash) { + ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return 5; + } + + while (node) { + if (node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0) { + match = true; + break; + } + + node = node->next; + } + + if (!match) { + char smd5[33]; + int i; + + for (i = 0; i < 16; i++) + sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); + + ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); + return 5; + } + } + + ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); + + // update session data + sd->account_id = acc.account_id; + sd->login_id1 = rnd(); + sd->login_id2 = rnd(); + safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); + sd->sex = acc.sex; + sd->group_id = acc.group_id; + + // update account data + timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); + safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); + acc.unban_time = 0; + acc.logincount++; + + accounts->save(accounts, &acc); + + if (sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM) + ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); + + return -1; // account OK } -void login_auth_ok(struct login_session_data* sd) +void login_auth_ok(struct login_session_data *sd) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - uint8 server_num, n; - uint32 subnet_char_ip; - struct auth_node* node; - int i; - - if( runflag != LOGINSERVER_ST_RUNNING ) - { - // players can only login while running - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1;// server closed - WFIFOSET(fd,3); - return; - } - - if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { - ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { - ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - server_num = 0; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - if( session_isActive(server[i].fd) ) - server_num++; - - if( server_num == 0 ) - {// if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - { - struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); - if( data ) - {// account is already marked as online! - if( data->char_server > -1 ) - {// Request char servers to kick this account out. [Skotlex] - uint8 buf[6]; - ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); - WBUFW(buf,0) = 0x2734; - WBUFL(buf,2) = sd->account_id; - charif_sendallwos(-1, buf, 6); - if( data->waiting_disconnect == INVALID_TIMER ) - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login - WFIFOSET(fd,3); - return; - } - else - if( data->char_server == -1 ) - {// client has authed but did not access char-server yet - // wipe previous session - idb_remove(auth_db, sd->account_id); - remove_online_user(sd->account_id); - data = NULL; - } - } - } - - login_log(ip, sd->userid, 100, "login ok"); - ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - memset(WFIFOP(fd,20), 0, 24); - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i ) - { - if( !session_isValid(server[i].fd) ) - continue; - - subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - WFIFOW(fd,47+n*32+28) = server[i].type; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; - } - WFIFOSET(fd,47+32*server_num); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->ip = ip; - node->version = sd->version; - node->clienttype = sd->clienttype; - idb_put(auth_db, sd->account_id, node); - - { - struct online_login_data* data; - - // mark client as 'online' - data = add_online_user(-1, sd->account_id); - - // schedule deletion of this node - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - } + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + uint8 server_num, n; + uint32 subnet_char_ip; + struct auth_node *node; + int i; + + if (runflag != LOGINSERVER_ST_RUNNING) { + // players can only login while running + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1;// server closed + WFIFOSET(fd,3); + return; + } + + if (login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect) { + ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } else if (login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect) { + ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + server_num = 0; + for (i = 0; i < ARRAYLENGTH(server); ++i) + if (session_isActive(server[i].fd)) + server_num++; + + if (server_num == 0) { + // if no char-server, don't send void list of servers, just disconnect the player with proper message + ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + { + struct online_login_data *data = (struct online_login_data *)idb_get(online_db, sd->account_id); + if (data) { + // account is already marked as online! + if (data->char_server > -1) { + // Request char servers to kick this account out. [Skotlex] + uint8 buf[6]; + ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); + WBUFW(buf,0) = 0x2734; + WBUFL(buf,2) = sd->account_id; + charif_sendallwos(-1, buf, 6); + if (data->waiting_disconnect == INVALID_TIMER) + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login + WFIFOSET(fd,3); + return; + } else if (data->char_server == -1) { + // client has authed but did not access char-server yet + // wipe previous session + idb_remove(auth_db, sd->account_id); + remove_online_user(sd->account_id); + data = NULL; + } + } + } + + login_log(ip, sd->userid, 100, "login ok"); + ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); + + WFIFOHEAD(fd,47+32*server_num); + WFIFOW(fd,0) = 0x69; + WFIFOW(fd,2) = 47+32*server_num; + WFIFOL(fd,4) = sd->login_id1; + WFIFOL(fd,8) = sd->account_id; + WFIFOL(fd,12) = sd->login_id2; + WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) + //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) + memset(WFIFOP(fd,20), 0, 24); + WFIFOW(fd,44) = 0; // unknown + WFIFOB(fd,46) = sex_str2num(sd->sex); + for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { + if (!session_isValid(server[i].fd)) + continue; + + subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] + WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); + WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); + WFIFOW(fd,47+n*32+26) = server[i].users; + WFIFOW(fd,47+n*32+28) = server[i].type; + WFIFOW(fd,47+n*32+30) = server[i].new_; + n++; + } + WFIFOSET(fd,47+32*server_num); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->ip = ip; + node->version = sd->version; + node->clienttype = sd->clienttype; + idb_put(auth_db, sd->account_id, node); + + { + struct online_login_data *data; + + // mark client as 'online' + data = add_online_user(-1, sd->account_id); + + // schedule deletion of this node + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + } } -void login_auth_failed(struct login_session_data* sd, int result) +void login_auth_failed(struct login_session_data *sd, int result) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - if (login_config.log_login) - { - const char* error; - switch( result ) { - case 0: error = "Unregistered ID."; break; // 0 = Unregistered ID - case 1: error = "Incorrect Password."; break; // 1 = Incorrect Password - case 2: error = "Account Expired."; break; // 2 = This ID is expired - case 3: error = "Rejected from server."; break; // 3 = Rejected from Server - case 4: error = "Blocked by GM."; break; // 4 = You have been blocked by the GM Team - case 5: error = "Not latest game EXE."; break; // 5 = Your Game's EXE file is not the latest version - case 6: error = "Banned."; break; // 6 = Your are Prohibited to log in until %s - case 7: error = "Server Over-population."; break; // 7 = Server is jammed due to over populated - case 8: error = "Account limit from company"; break; // 8 = No more accounts may be connected from this company - case 9: error = "Ban by DBA"; break; // 9 = MSI_REFUSE_BAN_BY_DBA - case 10: error = "Email not confirmed"; break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED - case 11: error = "Ban by GM"; break; // 11 = MSI_REFUSE_BAN_BY_GM - case 12: error = "Working in DB"; break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK - case 13: error = "Self Lock"; break; // 13 = MSI_REFUSE_SELF_LOCK - case 14: error = "Not Permitted Group"; break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 15: error = "Not Permitted Group"; break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 99: error = "Account gone."; break; // 99 = This ID has been totally erased - case 100: error = "Login info remains."; break; // 100 = Login information remains at %s - case 101: error = "Hacking investigation."; break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information - case 102: error = "Bug investigation."; break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation - case 103: error = "Deleting char."; break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being - case 104: error = "Deleting spouse char."; break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being - default : error = "Unknown Error."; break; - } - - login_log(ip, sd->userid, result, error); - } - - if( result == 1 && login_config.dynamic_pass_failure_ban ) - ipban_log(ip); // log failed password attempt - - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if( result != 6 ) - memset(WFIFOP(fd,3), '\0', 20); - else - {// 6 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format); - } - WFIFOSET(fd,23); + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + if (login_config.log_login) { + const char *error; + switch (result) { + case 0: + error = "Unregistered ID."; + break; // 0 = Unregistered ID + case 1: + error = "Incorrect Password."; + break; // 1 = Incorrect Password + case 2: + error = "Account Expired."; + break; // 2 = This ID is expired + case 3: + error = "Rejected from server."; + break; // 3 = Rejected from Server + case 4: + error = "Blocked by GM."; + break; // 4 = You have been blocked by the GM Team + case 5: + error = "Not latest game EXE."; + break; // 5 = Your Game's EXE file is not the latest version + case 6: + error = "Banned."; + break; // 6 = Your are Prohibited to log in until %s + case 7: + error = "Server Over-population."; + break; // 7 = Server is jammed due to over populated + case 8: + error = "Account limit from company"; + break; // 8 = No more accounts may be connected from this company + case 9: + error = "Ban by DBA"; + break; // 9 = MSI_REFUSE_BAN_BY_DBA + case 10: + error = "Email not confirmed"; + break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED + case 11: + error = "Ban by GM"; + break; // 11 = MSI_REFUSE_BAN_BY_GM + case 12: + error = "Working in DB"; + break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK + case 13: + error = "Self Lock"; + break; // 13 = MSI_REFUSE_SELF_LOCK + case 14: + error = "Not Permitted Group"; + break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 15: + error = "Not Permitted Group"; + break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 99: + error = "Account gone."; + break; // 99 = This ID has been totally erased + case 100: + error = "Login info remains."; + break; // 100 = Login information remains at %s + case 101: + error = "Hacking investigation."; + break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information + case 102: + error = "Bug investigation."; + break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation + case 103: + error = "Deleting char."; + break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being + case 104: + error = "Deleting spouse char."; + break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being + default : + error = "Unknown Error."; + break; + } + + login_log(ip, sd->userid, result, error); + } + + if (result == 1 && login_config.dynamic_pass_failure_ban) + ipban_log(ip); // log failed password attempt + + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = (uint8)result; + if (result != 6) + memset(WFIFOP(fd,3), '\0', 20); + else { + // 6 = Your are Prohibited to log in until %s + struct mmo_account acc; + time_t unban_time = (accounts->load_str(accounts, &acc, sd->userid)) ? acc.unban_time : 0; + timestamp2string((char *)WFIFOP(fd,3), 20, unban_time, login_config.date_format); + } + WFIFOSET(fd,23); } @@ -1298,428 +1294,400 @@ void login_auth_failed(struct login_session_data* sd, int result) //---------------------------------------------------------------------------------------- int parse_login(int fd) { - struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data; - int result; - - char ip[16]; - uint32 ipl = session[fd]->client_addr; - ip2str(ipl, ip); - - if( session[fd]->flag.eof ) - { - ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); - do_close(fd); - return 0; - } - - if( sd == NULL ) - { - // Perform ip-ban check - if( login_config.ipban && ipban_check(ipl) ) - { - ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); - login_log(ipl, "unknown", -3, "ip banned"); - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = 3; // 3 = Rejected from Server - WFIFOSET(fd,23); - set_eof(fd); - return 0; - } - - // create a session for this new connection - CREATE(session[fd]->session_data, struct login_session_data, 1); - sd = (struct login_session_data*)session[fd]->session_data; - sd->fd = fd; - } - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) - return 0; - RFIFOSKIP(fd,26); - break; - - // client md5 hash (binary) - case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (RFIFOREST(fd) < 18) - return 0; - - sd->has_client_hash = 1; - memcpy(sd->client_hash, RFIFOP(fd, 2), 16); - - RFIFOSKIP(fd,18); - break; - - // request client login (raw password) - case 0x0064: // S 0064 .L .24B .24B .B - case 0x0277: // S 0277 .L .24B .24B .B .16B .13B - case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd .L .24B .16B .B - case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c .L .24B .16B .B .13B(junk) - case 0x0825: // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B - { - size_t packet_len = RFIFOREST(fd); - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) - || (command == 0x01dd && packet_len < 47) - || (command == 0x01fa && packet_len < 48) - || (command == 0x027c && packet_len < 60) - || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) - return 0; - } - { - uint32 version; - char username[NAME_LENGTH]; - char password[NAME_LENGTH]; - unsigned char passhash[16]; - uint8 clienttype; - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - - // Shinryo: For the time being, just use token as password. - if(command == 0x0825) - { - char *accname = (char *)RFIFOP(fd, 9); - char *token = (char *)RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; - - version = RFIFOL(fd,4); - - if(uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) - { - login_auth_failed(sd, 3); - return 0; - } - - safestrncpy(username, accname, uAccLen + 1); - safestrncpy(password, token, uTokenLen + 1); - clienttype = RFIFOB(fd, 8); - } - else - { - version = RFIFOL(fd,2); - safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH); - if( israwpass ) - { - safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } - else - { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent - - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if( israwpass ) - { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, password, NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - } - else - { - ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); - bin2hex(sd->passwd, passhash, 16); // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - - if( sd->passwdenc != 0 && login_config.use_md5_passwds ) - { - login_auth_failed(sd, 3); // send "rejected from server" - return 0; - } - - result = mmo_auth(sd, false); - - if( result == -1 ) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); - { - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rnd() % 4); - MD5_Salt(sd->md5keylen, sd->md5key); - - WFIFOHEAD(fd,4 + sd->md5keylen); - WFIFOW(fd,0) = 0x01dc; - WFIFOW(fd,2) = 4 + sd->md5keylen; - memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - char server_name[20]; - char message[256]; - uint32 server_ip; - uint16 server_port; - uint16 type; - uint16 new_; - - safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - sd->version = login_config.client_version_to_connect; // hack to skip version check - server_ip = ntohl(RFIFOL(fd,54)); - server_port = ntohs(RFIFOW(fd,58)); - safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); - type = RFIFOW(fd,82); - new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); - - ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); - sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); - login_log(session[fd]->client_addr, sd->userid, 100, message); - - result = mmo_auth(sd, true); - if( runflag == LOGINSERVER_ST_RUNNING && - result == -1 && - sd->sex == 'S' && - sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && - !session_isValid(server[sd->account_id].fd) ) - { - ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); - safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); - server[sd->account_id].fd = fd; - server[sd->account_id].ip = server_ip; - server[sd->account_id].port = server_port; - server[sd->account_id].users = 0; - server[sd->account_id].type = type; - server[sd->account_id].new_ = new_; - - session[fd]->func_parse = parse_fromchar; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - // send connection success - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - else - { - ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } - } - return 0; // processing will continue elsewhere - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; - } - } - - return 0; + struct login_session_data *sd = (struct login_session_data *)session[fd]->session_data; + int result; + + char ip[16]; + uint32 ipl = session[fd]->client_addr; + ip2str(ipl, ip); + + if (session[fd]->flag.eof) { + ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); + do_close(fd); + return 0; + } + + if (sd == NULL) { + // Perform ip-ban check + if (login_config.ipban && ipban_check(ipl)) { + ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); + login_log(ipl, "unknown", -3, "ip banned"); + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = 3; // 3 = Rejected from Server + WFIFOSET(fd,23); + set_eof(fd); + return 0; + } + + // create a session for this new connection + CREATE(session[fd]->session_data, struct login_session_data, 1); + sd = (struct login_session_data *)session[fd]->session_data; + sd->fd = fd; + } + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. + if (RFIFOREST(fd) < 26) + return 0; + RFIFOSKIP(fd,26); + break; + + // client md5 hash (binary) + case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) + if (RFIFOREST(fd) < 18) + return 0; + + sd->has_client_hash = 1; + memcpy(sd->client_hash, RFIFOP(fd, 2), 16); + + RFIFOSKIP(fd,18); + break; + + // request client login (raw password) + case 0x0064: // S 0064 .L .24B .24B .B + case 0x0277: // S 0277 .L .24B .24B .B .16B .13B + case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B + // request client login (md5-hashed password) + case 0x01dd: // S 01dd .L .24B .16B .B + case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) + case 0x027c: // S 027c .L .24B .16B .B .13B(junk) + case 0x0825: { // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B + size_t packet_len = RFIFOREST(fd); + + if ((command == 0x0064 && packet_len < 55) + || (command == 0x0277 && packet_len < 84) + || (command == 0x02b0 && packet_len < 85) + || (command == 0x01dd && packet_len < 47) + || (command == 0x01fa && packet_len < 48) + || (command == 0x027c && packet_len < 60) + || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2)))) + return 0; + } + { + uint32 version; + char username[NAME_LENGTH]; + char password[NAME_LENGTH]; + unsigned char passhash[16]; + uint8 clienttype; + bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); + + // Shinryo: For the time being, just use token as password. + if (command == 0x0825) { + char *accname = (char *)RFIFOP(fd, 9); + char *token = (char *)RFIFOP(fd, 0x5C); + size_t uAccLen = strlen(accname); + size_t uTokenLen = RFIFOREST(fd) - 0x5C; + + version = RFIFOL(fd,4); + + if (uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) { + login_auth_failed(sd, 3); + return 0; + } + + safestrncpy(username, accname, uAccLen + 1); + safestrncpy(password, token, uTokenLen + 1); + clienttype = RFIFOB(fd, 8); + } else { + version = RFIFOL(fd,2); + safestrncpy(username, (const char *)RFIFOP(fd,6), NAME_LENGTH); + if (israwpass) { + safestrncpy(password, (const char *)RFIFOP(fd,30), NAME_LENGTH); + clienttype = RFIFOB(fd,54); + } else { + memcpy(passhash, RFIFOP(fd,30), 16); + clienttype = RFIFOB(fd,46); + } + } + RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + + sd->clienttype = clienttype; + sd->version = version; + safestrncpy(sd->userid, username, NAME_LENGTH); + if (israwpass) { + ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); + safestrncpy(sd->passwd, password, NAME_LENGTH); + if (login_config.use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + } else { + ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); + bin2hex(sd->passwd, passhash, 16); // raw binary data here! + sd->passwdenc = PASSWORDENC; + } + + if (sd->passwdenc != 0 && login_config.use_md5_passwds) { + login_auth_failed(sd, 3); // send "rejected from server" + return 0; + } + + result = mmo_auth(sd, false); + + if (result == -1) + login_auth_ok(sd); + else + login_auth_failed(sd, result); + } + break; + + case 0x01db: // Sending request of the coding key + RFIFOSKIP(fd,2); + { + memset(sd->md5key, '\0', sizeof(sd->md5key)); + sd->md5keylen = (uint16)(12 + rnd() % 4); + MD5_Salt(sd->md5keylen, sd->md5key); + + WFIFOHEAD(fd,4 + sd->md5keylen); + WFIFOW(fd,0) = 0x01dc; + WFIFOW(fd,2) = 4 + sd->md5keylen; + memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2710: // Connection request of a char-server + if (RFIFOREST(fd) < 86) + return 0; + { + char server_name[20]; + char message[256]; + uint32 server_ip; + uint16 server_port; + uint16 type; + uint16 new_; + + safestrncpy(sd->userid, (char *)RFIFOP(fd,2), NAME_LENGTH); + safestrncpy(sd->passwd, (char *)RFIFOP(fd,26), NAME_LENGTH); + if (login_config.use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + sd->version = login_config.client_version_to_connect; // hack to skip version check + server_ip = ntohl(RFIFOL(fd,54)); + server_port = ntohs(RFIFOW(fd,58)); + safestrncpy(server_name, (char *)RFIFOP(fd,60), 20); + type = RFIFOW(fd,82); + new_ = RFIFOW(fd,84); + RFIFOSKIP(fd,86); + + ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); + sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); + login_log(session[fd]->client_addr, sd->userid, 100, message); + + result = mmo_auth(sd, true); + if (runflag == LOGINSERVER_ST_RUNNING && + result == -1 && + sd->sex == 'S' && + sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && + !session_isValid(server[sd->account_id].fd)) { + ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); + safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); + server[sd->account_id].fd = fd; + server[sd->account_id].ip = server_ip; + server[sd->account_id].port = server_port; + server[sd->account_id].users = 0; + server[sd->account_id].type = type; + server[sd->account_id].new_ = new_; + + session[fd]->func_parse = parse_fromchar; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + // send connection success + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } else { + ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } + } + return 0; // processing will continue elsewhere + + default: + ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); + set_eof(fd); + return 0; + } + } + + return 0; } void login_set_defaults() { - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - login_config.ipban_cleanup_interval = 60; - login_config.ip_sync_interval = 0; - login_config.log_login = true; - safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); - login_config.console = false; - login_config.new_account_flag = true; - login_config.new_acc_length_limit = true; - login_config.use_md5_passwds = false; - login_config.group_id_to_connect = -1; - login_config.min_group_id_to_connect = -1; - login_config.check_client_version = false; - login_config.client_version_to_connect = 20; - - login_config.ipban = true; - login_config.dynamic_pass_failure_ban = true; - login_config.dynamic_pass_failure_ban_interval = 5; - login_config.dynamic_pass_failure_ban_limit = 7; - login_config.dynamic_pass_failure_ban_duration = 5; - login_config.use_dnsbl = false; - safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); - safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); - - login_config.client_hash_check = 0; - login_config.client_hash_nodes = NULL; + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + login_config.ipban_cleanup_interval = 60; + login_config.ip_sync_interval = 0; + login_config.log_login = true; + safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); + login_config.console = false; + login_config.new_account_flag = true; + login_config.new_acc_length_limit = true; + login_config.use_md5_passwds = false; + login_config.group_id_to_connect = -1; + login_config.min_group_id_to_connect = -1; + login_config.check_client_version = false; + login_config.client_version_to_connect = 20; + + login_config.ipban = true; + login_config.dynamic_pass_failure_ban = true; + login_config.dynamic_pass_failure_ban_interval = 5; + login_config.dynamic_pass_failure_ban_limit = 7; + login_config.dynamic_pass_failure_ban_duration = 5; + login_config.use_dnsbl = false; + safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); + safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); + + login_config.client_hash_check = 0; + login_config.client_hash_nodes = NULL; } //----------------------------------- // Reading main configuration file //----------------------------------- -int login_config_read(const char* cfgName) +int login_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("Configuration file (%s) not found.\n", cfgName); - return 1; - } - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) - continue; - - if(!strcmpi(w1,"timestamp_format")) - strncpy(timestamp_format, w2, 20); - else if(!strcmpi(w1,"stdout_with_ansisequence")) - stdout_with_ansisequence = config_switch(w2); - else if(!strcmpi(w1,"console_silent")) { - msg_silent = atoi(w2); - if( msg_silent ) /* only bother if we actually have this enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } - else if( !strcmpi(w1, "bind_ip") ) { - char ip_str[16]; - login_config.login_ip = host2ip(w2); - if( login_config.login_ip ) - ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); - } - else if( !strcmpi(w1, "login_port") ) { - login_config.login_port = (uint16)atoi(w2); - } - else if(!strcmpi(w1, "log_login")) - login_config.log_login = (bool)config_switch(w2); - - else if(!strcmpi(w1, "new_account")) - login_config.new_account_flag = (bool)config_switch(w2); - else if(!strcmpi(w1, "new_acc_length_limit")) - login_config.new_acc_length_limit = (bool)config_switch(w2); - else if(!strcmpi(w1, "start_limited_time")) - login_config.start_limited_time = atoi(w2); - else if(!strcmpi(w1, "check_client_version")) - login_config.check_client_version = (bool)config_switch(w2); - else if(!strcmpi(w1, "client_version_to_connect")) - login_config.client_version_to_connect = strtoul(w2, NULL, 10); - else if(!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = (bool)config_switch(w2); - else if(!strcmpi(w1, "group_id_to_connect")) - login_config.group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "min_group_id_to_connect")) - login_config.min_group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "date_format")) - safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); - else if(!strcmpi(w1, "console")) - login_config.console = (bool)config_switch(w2); - else if(!strcmpi(w1, "allowed_regs")) //account flood protection system - allowed_regs = atoi(w2); - else if(!strcmpi(w1, "time_allowed")) - time_allowed = atoi(w2); - else if(!strcmpi(w1, "use_dnsbl")) - login_config.use_dnsbl = (bool)config_switch(w2); - else if(!strcmpi(w1, "dnsbl_servers")) - safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); - else if(!strcmpi(w1, "ipban_cleanup_interval")) - login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); - else if(!strcmpi(w1, "ip_sync_interval")) - login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if(!strcmpi(w1, "client_hash_check")) - login_config.client_hash_check = config_switch(w2); - else if(!strcmpi(w1, "client_hash")) { - int group = 0; - char md5[33]; - int i; - - if (sscanf(w2, "%d, %32s", &group, md5) == 2) { - struct client_hash_node *nnode; - CREATE(nnode, struct client_hash_node, 1); - - for (i = 0; i < 32; i += 2) { - char buf[3]; - unsigned int byte; - - memcpy(buf, &md5[i], 2); - buf[2] = 0; - - sscanf(buf, "%x", &byte); - nnode->hash[i / 2] = (uint8)(byte & 0xFF); - } - - nnode->group_id = group; - nnode->next = login_config.client_hash_nodes; - - login_config.client_hash_nodes = nnode; - } - } - else if(!strcmpi(w1, "import")) - login_config_read(w2); - else - if(!strcmpi(w1, "account.engine")) - safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); - else - {// try the account engines - int i; - for( i = 0; account_engines[i].constructor; ++i ) - { - AccountDB* db = account_engines[i].db; - if( db && db->set_property(db, w1, w2) ) - break; - } - // try others - ipban_config_read(w1, w2); - loginlog_config_read(w1, w2); - } - } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("Configuration file (%s) not found.\n", cfgName); + return 1; + } + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) + continue; + + if (!strcmpi(w1,"timestamp_format")) + strncpy(timestamp_format, w2, 20); + else if (!strcmpi(w1,"stdout_with_ansisequence")) + stdout_with_ansisequence = config_switch(w2); + else if (!strcmpi(w1,"console_silent")) { + msg_silent = atoi(w2); + if (msg_silent) /* only bother if we actually have this enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } else if (!strcmpi(w1, "bind_ip")) { + char ip_str[16]; + login_config.login_ip = host2ip(w2); + if (login_config.login_ip) + ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); + } else if (!strcmpi(w1, "login_port")) { + login_config.login_port = (uint16)atoi(w2); + } else if (!strcmpi(w1, "log_login")) + login_config.log_login = (bool)config_switch(w2); + + else if (!strcmpi(w1, "new_account")) + login_config.new_account_flag = (bool)config_switch(w2); + else if (!strcmpi(w1, "new_acc_length_limit")) + login_config.new_acc_length_limit = (bool)config_switch(w2); + else if (!strcmpi(w1, "start_limited_time")) + login_config.start_limited_time = atoi(w2); + else if (!strcmpi(w1, "check_client_version")) + login_config.check_client_version = (bool)config_switch(w2); + else if (!strcmpi(w1, "client_version_to_connect")) + login_config.client_version_to_connect = strtoul(w2, NULL, 10); + else if (!strcmpi(w1, "use_MD5_passwords")) + login_config.use_md5_passwds = (bool)config_switch(w2); + else if (!strcmpi(w1, "group_id_to_connect")) + login_config.group_id_to_connect = atoi(w2); + else if (!strcmpi(w1, "min_group_id_to_connect")) + login_config.min_group_id_to_connect = atoi(w2); + else if (!strcmpi(w1, "date_format")) + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); + else if (!strcmpi(w1, "console")) + login_config.console = (bool)config_switch(w2); + else if (!strcmpi(w1, "allowed_regs")) //account flood protection system + allowed_regs = atoi(w2); + else if (!strcmpi(w1, "time_allowed")) + time_allowed = atoi(w2); + else if (!strcmpi(w1, "use_dnsbl")) + login_config.use_dnsbl = (bool)config_switch(w2); + else if (!strcmpi(w1, "dnsbl_servers")) + safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); + else if (!strcmpi(w1, "ipban_cleanup_interval")) + login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); + else if (!strcmpi(w1, "ip_sync_interval")) + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. + else if (!strcmpi(w1, "client_hash_check")) + login_config.client_hash_check = config_switch(w2); + else if (!strcmpi(w1, "client_hash")) { + int group = 0; + char md5[33]; + int i; + + if (sscanf(w2, "%d, %32s", &group, md5) == 2) { + struct client_hash_node *nnode; + CREATE(nnode, struct client_hash_node, 1); + + for (i = 0; i < 32; i += 2) { + char buf[3]; + unsigned int byte; + + memcpy(buf, &md5[i], 2); + buf[2] = 0; + + sscanf(buf, "%x", &byte); + nnode->hash[i / 2] = (uint8)(byte & 0xFF); + } + + nnode->group_id = group; + nnode->next = login_config.client_hash_nodes; + + login_config.client_hash_nodes = nnode; + } + } else if (!strcmpi(w1, "import")) + login_config_read(w2); + else if (!strcmpi(w1, "account.engine")) + safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); + else { + // try the account engines + int i; + for (i = 0; account_engines[i].constructor; ++i) { + AccountDB *db = account_engines[i].db; + if (db && db->set_property(db, w1, w2)) + break; + } + // try others + ipban_config_read(w1, w2); + loginlog_config_read(w1, w2); + } + } + fclose(fp); + ShowInfo("Finished reading %s.\n", cfgName); + return 0; } /// Get the engine selected in the config settings. /// Updates the config setting with the selected engine if 'auto'. -static AccountDB* get_account_engine(void) +static AccountDB *get_account_engine(void) { - int i; - bool get_first = (strcmp(login_config.account_engine,"auto") == 0); - - for( i = 0; account_engines[i].constructor; ++i ) - { - char name[sizeof(login_config.account_engine)]; - AccountDB* db = account_engines[i].db; - if( db && db->get_property(db, "engine.name", name, sizeof(name)) && - (get_first || strcmp(name, login_config.account_engine) == 0) ) - { - if( get_first ) - safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); - return db; - } - } - return NULL; + int i; + bool get_first = (strcmp(login_config.account_engine,"auto") == 0); + + for (i = 0; account_engines[i].constructor; ++i) { + char name[sizeof(login_config.account_engine)]; + AccountDB *db = account_engines[i].db; + if (db && db->get_property(db, "engine.name", name, sizeof(name)) && + (get_first || strcmp(name, login_config.account_engine) == 0)) { + if (get_first) + safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); + return db; + } + } + return NULL; } //-------------------------------------- @@ -1727,47 +1695,44 @@ static AccountDB* get_account_engine(void) //-------------------------------------- void do_final(void) { - int i; - struct client_hash_node *hn = login_config.client_hash_nodes; - - while (hn) - { - struct client_hash_node *tmp = hn; - hn = hn->next; - aFree(tmp); - } - - login_log(0, "login server", 100, "login server shutdown"); - ShowStatus("Terminating...\n"); - - if( login_config.log_login ) - loginlog_final(); - - ipban_final(); - - for( i = 0; account_engines[i].constructor; ++i ) - {// destroy all account engines - AccountDB* db = account_engines[i].db; - if( db ) - { - db->destroy(db); - account_engines[i].db = NULL; - } - } - accounts = NULL; // destroyed in account_engines - online_db->destroy(online_db, NULL); - auth_db->destroy(auth_db, NULL); - - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_destroy(i); - - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } - - ShowStatus("Finished.\n"); + int i; + struct client_hash_node *hn = login_config.client_hash_nodes; + + while (hn) { + struct client_hash_node *tmp = hn; + hn = hn->next; + aFree(tmp); + } + + login_log(0, "login server", 100, "login server shutdown"); + ShowStatus("Terminating...\n"); + + if (login_config.log_login) + loginlog_final(); + + ipban_final(); + + for (i = 0; account_engines[i].constructor; ++i) { + // destroy all account engines + AccountDB *db = account_engines[i].db; + if (db) { + db->destroy(db); + account_engines[i].db = NULL; + } + } + accounts = NULL; // destroyed in account_engines + online_db->destroy(online_db, NULL); + auth_db->destroy(auth_db, NULL); + + for (i = 0; i < ARRAYLENGTH(server); ++i) + chrif_server_destroy(i); + + if (login_fd != -1) { + do_close(login_fd); + login_fd = -1; + } + + ShowStatus("Finished.\n"); } //------------------------------ @@ -1780,104 +1745,101 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_LOGIN; + SERVER_TYPE = ATHENA_SERVER_LOGIN; } /// Called when a terminate signal is received. void do_shutdown(void) { - if( runflag != LOGINSERVER_ST_SHUTDOWN ) - { - int id; - runflag = LOGINSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - chrif_server_reset(id); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if (runflag != LOGINSERVER_ST_SHUTDOWN) { + int id; + runflag = LOGINSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + chrif_server_reset(id); + flush_fifos(); + runflag = CORE_ST_STOP; + } } //------------------------------ // Login server initialization //------------------------------ -int do_init(int argc, char** argv) +int do_init(int argc, char **argv) { - int i; - - // intialize engines (to accept config settings) - for( i = 0; account_engines[i].constructor; ++i ) - account_engines[i].db = account_engines[i].constructor(); - - // read login-server configuration - login_set_defaults(); - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); - - rnd_init(); - - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_init(i); - - // initialize logging - if( login_config.log_login ) - loginlog_init(); - - // initialize static and dynamic ipban system - ipban_init(); - - // Online user database init - online_db = idb_alloc(DB_OPT_RELEASE_DATA); - add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); - - // Interserver auth init - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - - // set default parser as parse_login function - set_defaultparse(parse_login); - - // every 10 minutes cleanup online account db. - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); - - // add timer to detect ip address change and perform update - if (login_config.ip_sync_interval) { - add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); - } - - // Account database init - accounts = get_account_engine(); - if( accounts == NULL ) { - ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } else { - - if(!accounts->init(accounts)) { - ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } - } - - if( login_config.console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - // server port open & binding - login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - - if( runflag != CORE_ST_STOP ) - { - shutdown_callback = do_shutdown; - runflag = LOGINSERVER_ST_RUNNING; - } - - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); - login_log(0, "login server", 100, "login server started"); - - return 0; + int i; + + // intialize engines (to accept config settings) + for (i = 0; account_engines[i].constructor; ++i) + account_engines[i].db = account_engines[i].constructor(); + + // read login-server configuration + login_set_defaults(); + login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); + + rnd_init(); + + for (i = 0; i < ARRAYLENGTH(server); ++i) + chrif_server_init(i); + + // initialize logging + if (login_config.log_login) + loginlog_init(); + + // initialize static and dynamic ipban system + ipban_init(); + + // Online user database init + online_db = idb_alloc(DB_OPT_RELEASE_DATA); + add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); + + // Interserver auth init + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + + // set default parser as parse_login function + set_defaultparse(parse_login); + + // every 10 minutes cleanup online account db. + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + + // add timer to detect ip address change and perform update + if (login_config.ip_sync_interval) { + add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); + add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); + } + + // Account database init + accounts = get_account_engine(); + if (accounts == NULL) { + ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } else { + + if (!accounts->init(accounts)) { + ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } + } + + if (login_config.console) { + //##TODO invoke a CONSOLE_START plugin event + } + + // server port open & binding + login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); + + if (runflag != CORE_ST_STOP) { + shutdown_callback = do_shutdown; + runflag = LOGINSERVER_ST_RUNNING; + } + + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); + login_log(0, "login server", 100, "login server started"); + + return 0; } diff --git a/src/login/login.h b/src/login/login.h index bedf5e179..97335aa89 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -7,11 +7,10 @@ #include "../common/mmo.h" // NAME_LENGTH,SEX_* #include "../common/core.h" // CORE_ST_LAST -enum E_LOGINSERVER_ST -{ - LOGINSERVER_ST_RUNNING = CORE_ST_LAST, - LOGINSERVER_ST_SHUTDOWN, - LOGINSERVER_ST_LAST +enum E_LOGINSERVER_ST { + LOGINSERVER_ST_RUNNING = CORE_ST_LAST, + LOGINSERVER_ST_SHUTDOWN, + LOGINSERVER_ST_LAST }; #define LOGIN_CONF_NAME "conf/login_athena.conf" @@ -21,74 +20,74 @@ enum E_LOGINSERVER_ST #define PASSWORDENC 3 struct login_session_data { - int account_id; - long login_id1; - long login_id2; - char sex;// 'F','M','S' - - char userid[NAME_LENGTH]; - char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - int passwdenc; - char md5key[20]; - uint16 md5keylen; - - char lastlogin[24]; - uint8 group_id; - uint8 clienttype; - uint32 version; - - uint8 client_hash[16]; - int has_client_hash; - - int fd; + int account_id; + long login_id1; + long login_id2; + char sex;// 'F','M','S' + + char userid[NAME_LENGTH]; + char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + int passwdenc; + char md5key[20]; + uint16 md5keylen; + + char lastlogin[24]; + uint8 group_id; + uint8 clienttype; + uint32 version; + + uint8 client_hash[16]; + int has_client_hash; + + int fd; }; struct mmo_char_server { - char name[20]; - int fd; - uint32 ip; - uint16 port; - uint16 users; // user count on this server - uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P - uint16 new_; // should display as 'new'? + char name[20]; + int fd; + uint32 ip; + uint16 port; + uint16 users; // user count on this server + uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P + uint16 new_; // should display as 'new'? }; struct client_hash_node { - int group_id; - uint8 hash[16]; - struct client_hash_node *next; + int group_id; + uint8 hash[16]; + struct client_hash_node *next; }; struct Login_Config { - uint32 login_ip; // the address to bind to - uint16 login_port; // the port to bind to - unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans - unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) - bool log_login; // whether to log login server actions or not - char date_format[32]; // date format used in messages - bool console; // console input system enabled? - bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? - int start_limited_time; // new account expiration time (-1: unlimited) - bool use_md5_passwds; // work with password hashes instead of plaintext passwords? - int group_id_to_connect; // required group id to connect - int min_group_id_to_connect; // minimum group id to connect - bool check_client_version; // check the clientversion set in the clientinfo ? - uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) - - bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? - bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? - unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures - unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban - unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban - bool use_dnsbl; // dns blacklist blocking ? - char dnsbl_servs[1024]; // comma-separated list of dnsbl servers - - char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) - - int client_hash_check; // flags for checking client md5 - struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group + uint32 login_ip; // the address to bind to + uint16 login_port; // the port to bind to + unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans + unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) + bool log_login; // whether to log login server actions or not + char date_format[32]; // date format used in messages + bool console; // console input system enabled? + bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? + int start_limited_time; // new account expiration time (-1: unlimited) + bool use_md5_passwds; // work with password hashes instead of plaintext passwords? + int group_id_to_connect; // required group id to connect + int min_group_id_to_connect; // minimum group id to connect + bool check_client_version; // check the clientversion set in the clientinfo ? + uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) + + bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? + bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? + unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures + unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban + unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban + bool use_dnsbl; // dns blacklist blocking ? + char dnsbl_servs[1024]; // comma-separated list of dnsbl servers + + char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) + + int client_hash_check; // flags for checking client md5 + struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group }; #define sex_num2str(num) ( (num == SEX_FEMALE ) ? 'F' : (num == SEX_MALE ) ? 'M' : 'S' ) diff --git a/src/login/loginlog.h b/src/login/loginlog.h index a1ffaae85..63621c50a 100644 --- a/src/login/loginlog.h +++ b/src/login/loginlog.h @@ -6,10 +6,10 @@ unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes); -void login_log(uint32 ip, const char* username, int rcode, const char* message); +void login_log(uint32 ip, const char *username, int rcode, const char *message); bool loginlog_init(void); bool loginlog_final(void); -bool loginlog_config_read(const char* w1, const char* w2); +bool loginlog_config_read(const char *w1, const char *w2); #endif // __LOGINLOG_H_INCLUDED__ diff --git a/src/login/loginlog_sql.c b/src/login/loginlog_sql.c index d61172697..2d8a17528 100644 --- a/src/login/loginlog_sql.c +++ b/src/login/loginlog_sql.c @@ -25,160 +25,145 @@ static char log_db_database[32] = ""; static char log_codepage[32] = ""; static char log_login_db[256] = "loginlog"; -static Sql* sql_handle = NULL; +static Sql *sql_handle = NULL; static bool enabled = false; // Returns the number of failed login attemps by the ip in the last minutes. unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) { - unsigned long failures = 0; - - if( !enabled ) - return 0; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", - log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip. - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); - failures = strtoul(data, NULL, 10); - Sql_FreeResult(sql_handle); - } - return failures; + unsigned long failures = 0; + + if (!enabled) + return 0; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", + log_login_db, ip2str(ip,NULL), minutes)) // how many times failed account? in one ip. + Sql_ShowDebug(sql_handle); + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + failures = strtoul(data, NULL, 10); + Sql_FreeResult(sql_handle); + } + return failures; } /*============================================= * Records an event in the login log *---------------------------------------------*/ -void login_log(uint32 ip, const char* username, int rcode, const char* message) +void login_log(uint32 ip, const char *username, int rcode, const char *message) { - char esc_username[NAME_LENGTH*2+1]; - char esc_message[255*2+1]; - int retcode; + char esc_username[NAME_LENGTH*2+1]; + char esc_message[255*2+1]; + int retcode; - if( !enabled ) - return; + if (!enabled) + return; - Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); + Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); - retcode = Sql_Query(sql_handle, - "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", - log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); + retcode = Sql_Query(sql_handle, + "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", + log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); - if( retcode != SQL_SUCCESS ) - Sql_ShowDebug(sql_handle); + if (retcode != SQL_SUCCESS) + Sql_ShowDebug(sql_handle); } bool loginlog_init(void) { - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - if( log_db_hostname[0] != '\0' ) - {// local settings - username = log_db_username; - password = log_db_password; - hostname = log_db_hostname; - port = log_db_port; - database = log_db_database; - codepage = log_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - sql_handle = Sql_Malloc(); - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - enabled = true; - - return true; + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + if (log_db_hostname[0] != '\0') { + // local settings + username = log_db_username; + password = log_db_password; + hostname = log_db_hostname; + port = log_db_port; + database = log_db_database; + codepage = log_codepage; + } else { + // global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + sql_handle = Sql_Malloc(); + + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + enabled = true; + + return true; } bool loginlog_final(void) { - Sql_Free(sql_handle); - sql_handle = NULL; - return true; + Sql_Free(sql_handle); + sql_handle = NULL; + return true; } -bool loginlog_config_read(const char* key, const char* value) +bool loginlog_config_read(const char *key, const char *value) { - const char* signature; - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - if( strcmpi(key, "log_db_ip") == 0 ) - safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); - else - if( strcmpi(key, "log_db_port") == 0 ) - log_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "log_db_id") == 0 ) - safestrncpy(log_db_username, value, sizeof(log_db_username)); - else - if( strcmpi(key, "log_db_pw") == 0 ) - safestrncpy(log_db_password, value, sizeof(log_db_password)); - else - if( strcmpi(key, "log_db_db") == 0 ) - safestrncpy(log_db_database, value, sizeof(log_db_database)); - else - if( strcmpi(key, "log_codepage") == 0 ) - safestrncpy(log_codepage, value, sizeof(log_codepage)); - else - if( strcmpi(key, "log_login_db") == 0 ) - safestrncpy(log_login_db, value, sizeof(log_login_db)); - else - return false; - - return true; + const char *signature; + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + if (strcmpi(key, "log_db_ip") == 0) + safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); + else if (strcmpi(key, "log_db_port") == 0) + log_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "log_db_id") == 0) + safestrncpy(log_db_username, value, sizeof(log_db_username)); + else if (strcmpi(key, "log_db_pw") == 0) + safestrncpy(log_db_password, value, sizeof(log_db_password)); + else if (strcmpi(key, "log_db_db") == 0) + safestrncpy(log_db_database, value, sizeof(log_db_database)); + else if (strcmpi(key, "log_codepage") == 0) + safestrncpy(log_codepage, value, sizeof(log_codepage)); + else if (strcmpi(key, "log_login_db") == 0) + safestrncpy(log_login_db, value, sizeof(log_login_db)); + else + return false; + + return true; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 394f4fb11..33a389db9 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -61,100 +61,97 @@ typedef struct AliasInfo AliasInfo; int atcmd_binding_count = 0; struct AtCommandInfo { - char command[ATCOMMAND_LENGTH]; - AtCommandFunc func; - char* at_groups;/* quick @commands "can-use" lookup */ - char* char_groups;/* quick @charcommands "can-use" lookup */ + char command[ATCOMMAND_LENGTH]; + AtCommandFunc func; + char *at_groups;/* quick @commands "can-use" lookup */ + char *char_groups;/* quick @charcommands "can-use" lookup */ }; struct AliasInfo { - AtCommandInfo *command; - char alias[ATCOMMAND_LENGTH]; + AtCommandInfo *command; + char alias[ATCOMMAND_LENGTH]; }; char atcommand_symbol = '@'; // first char of the commands char charcommand_symbol = '#'; -static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) -static DBMap* atcommand_db = NULL; //name -> AtCommandInfo -static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo +static char *msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +static DBMap *atcommand_db = NULL; //name -> AtCommandInfo +static DBMap *atcommand_alias_db = NULL; //alias -> AtCommandInfo static config_t atcommand_config; static char atcmd_output[CHAT_SIZE_MAX]; static char atcmd_player_name[NAME_LENGTH]; -static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help -static const char* atcommand_checkalias(const char *aliasname); // @help -static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help +static AtCommandInfo *get_atcommandinfo_byname(const char *name); // @help +static const char *atcommand_checkalias(const char *aliasname); // @help +static void atcommand_get_suggestions(struct map_session_data *sd, const char *name, bool atcommand); // @help // @commands (script-based) -struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { - int i = 0; +struct atcmd_binding_data *get_atcommandbind_byname(const char *name) { + int i = 0; - if( *name == atcommand_symbol || *name == charcommand_symbol ) - name++; // for backwards compatibility + if (*name == atcommand_symbol || *name == charcommand_symbol) + name++; // for backwards compatibility - ARR_FIND( 0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0 ); + ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0); - return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL; + return (i < atcmd_binding_count) ? atcmd_binding[i] : NULL; } //----------------------------------------------------------- // Return the message string of the specified number by [Yor] //----------------------------------------------------------- -const char* msg_txt(int msg_number) +const char *msg_txt(int msg_number) { - if (msg_number >= 0 && msg_number < MAX_MSG && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; + if (msg_number >= 0 && msg_number < MAX_MSG && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "??"; + return "??"; } /*========================================== * Read Message Data *------------------------------------------*/ -int msg_config_read(const char* cfgName) +int msg_config_read(const char *cfgName) { - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else - { - msg_number = atoi(w1); - if (msg_number >= 0 && msg_number < MAX_MSG) - { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); - strcpy(msg_table[msg_number],w2); - } - } - } + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else { + msg_number = atoi(w1); + if (msg_number >= 0 && msg_number < MAX_MSG) { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); + strcpy(msg_table[msg_number],w2); + } + } + } - fclose(fp); + fclose(fp); - return 0; + return 0; } /*========================================== @@ -162,9 +159,9 @@ int msg_config_read(const char* cfgName) *------------------------------------------*/ void do_final_msg(void) { - int i; - for (i = 0; i < MAX_MSG; i++) - aFree(msg_table[i]); + int i; + for (i = 0; i < MAX_MSG; i++) + aFree(msg_table[i]); } /** @@ -173,34 +170,34 @@ void do_final_msg(void) * @param name the name of the command to retrieve help information for * @return the string associated with the command, or NULL */ -static const char* atcommand_help_string(const char* command) +static const char *atcommand_help_string(const char *command) { - const char* str = NULL; - config_setting_t* info; + const char *str = NULL; + config_setting_t *info; - if( *command == atcommand_symbol || *command == charcommand_symbol ) - {// remove the prefix symbol for the raw name of the command - command ++; - } + if (*command == atcommand_symbol || *command == charcommand_symbol) { + // remove the prefix symbol for the raw name of the command + command ++; + } - // convert alias to the real command name - command = atcommand_checkalias(command); + // convert alias to the real command name + command = atcommand_checkalias(command); - // attept to find the first default help command - info = config_lookup(&atcommand_config, "help"); + // attept to find the first default help command + info = config_lookup(&atcommand_config, "help"); - if( info == NULL ) - {// failed to find the help property in the configuration file - return NULL; - } + if (info == NULL) { + // failed to find the help property in the configuration file + return NULL; + } - if( !config_setting_lookup_string( info, command, &str ) ) - {// failed to find the matching help string - return NULL; - } + if (!config_setting_lookup_string(info, command, &str)) { + // failed to find the matching help string + return NULL; + } - // push the result from the method - return str; + // push the result from the method + return str; } @@ -209,228 +206,243 @@ static const char* atcommand_help_string(const char* command) *------------------------------------------*/ ACMD_FUNC(send) { - int len=0,off,end,type; - long num; + int len=0,off,end,type; + long num; - // read message type as hex number (without the 0x) - if(!message || !*message || - !((sscanf(message, "len %x", &type)==1 && (len=1)) - || sscanf(message, "%x", &type)==1) ) - { - int i; - for (i = 900; i <= 903; ++i) - clif_displaymessage(fd, msg_txt(i)); - return -1; - } + // read message type as hex number (without the 0x) + if (!message || !*message || + !((sscanf(message, "len %x", &type)==1 && (len=1)) + || sscanf(message, "%x", &type)==1)) { + int i; + for (i = 900; i <= 903; ++i) + clif_displaymessage(fd, msg_txt(i)); + return -1; + } #define PARSE_ERROR(error,p) \ - {\ - clif_displaymessage(fd, (error));\ - sprintf(atcmd_output, ">%s", (p));\ - clif_displaymessage(fd, atcmd_output);\ - } -//define PARSE_ERROR + {\ + clif_displaymessage(fd, (error));\ + sprintf(atcmd_output, ">%s", (p));\ + clif_displaymessage(fd, atcmd_output);\ + } + //define PARSE_ERROR #define CHECK_EOS(p) \ - if(*(p) == 0){\ - clif_displaymessage(fd, "Unexpected end of string");\ - return -1;\ - } -//define CHECK_EOS + if(*(p) == 0){\ + clif_displaymessage(fd, "Unexpected end of string");\ + return -1;\ + } + //define CHECK_EOS #define SKIP_VALUE(p) \ - {\ - while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ - while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ - } -//define SKIP_VALUE + {\ + while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ + while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ + } + //define SKIP_VALUE #define GET_VALUE(p,num) \ - {\ - if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ - PARSE_ERROR("Invalid number in:",(p));\ - return -1;\ - }\ - } -//define GET_VALUE - - if (type > 0 && type < MAX_PACKET_DB) { - - if(len) - {// show packet length - sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d - clif_displaymessage(fd, atcmd_output); - return 0; - } - - len=packet_db[sd->packet_ver][type].len; - off=2; - if(len == 0) - {// unknown packet - ERROR - sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x - clif_displaymessage(fd, atcmd_output); - return -1; - } else if(len == -1) - {// dynamic packet - len=SHRT_MAX-4; // maximum length - off=4; - } - WFIFOHEAD(fd, len); - WFIFOW(fd,0)=TOW(type); - - // parse packet contents - SKIP_VALUE(message); - while(*message != 0 && off < len){ - if(ISDIGIT(*message) || *message == '-' || *message == '+') - {// default (byte) - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if(TOUPPER(*message) == 'B') - {// byte - ++message; - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if(TOUPPER(*message) == 'W') - {// word (2 bytes) - ++message; - GET_VALUE(message,num); - WFIFOW(fd,off)=TOW(num); - off+=2; - } else if(TOUPPER(*message) == 'L') - {// long word (4 bytes) - ++message; - GET_VALUE(message,num); - WFIFOL(fd,off)=TOL(num); - off+=4; - } else if(TOUPPER(*message) == 'S') - {// string - escapes are valid - // get string length - num <= 0 means not fixed length (default) - ++message; - if(*message == '"'){ - num=0; - } else { - GET_VALUE(message,num); - while(*message != '"') - {// find start of string - if(*message == 0 || ISSPACE(*message)){ - PARSE_ERROR(msg_txt(906),message); // Not a string: - return -1; - } - ++message; - } - } - - // parse string - ++message; - CHECK_EOS(message); - end=(num<=0? 0: min(off+((int)num),len)); - for(; *message != '"' && (off < end || end == 0); ++off){ - if(*message == '\\'){ - ++message; - CHECK_EOS(message); - switch(*message){ - case 'a': num=0x07; break; // Bell - case 'b': num=0x08; break; // Backspace - case 't': num=0x09; break; // Horizontal tab - case 'n': num=0x0A; break; // Line feed - case 'v': num=0x0B; break; // Vertical tab - case 'f': num=0x0C; break; // Form feed - case 'r': num=0x0D; break; // Carriage return - case 'e': num=0x1B; break; // Escape - default: num=*message; break; - case 'x': // Hexadecimal - { - ++message; - CHECK_EOS(message); - if(!ISXDIGIT(*message)){ - PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: - return -1; - } - num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - if(ISXDIGIT(*message)){ - ++message; - CHECK_EOS(message); - num<<=8; - num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - } - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - continue; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': // Octal - { - num=*message-'0'; // 1st octal digit - ++message; - CHECK_EOS(message); - if(ISDIGIT(*message) && *message < '8'){ - num<<=3; - num+=*message-'0'; // 2nd octal digit - ++message; - CHECK_EOS(message); - if(ISDIGIT(*message) && *message < '8'){ - num<<=3; - num+=*message-'0'; // 3rd octal digit - ++message; - CHECK_EOS(message); - } - } - WFIFOB(fd,off)=TOB(num); - continue; - } - } - } else - num=*message; - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - }//for - while(*message != '"') - {// ignore extra characters - ++message; - CHECK_EOS(message); - } - - // terminate the string - if(off < end) - {// fill the rest with 0's - memset(WFIFOP(fd,off),0,end-off); - off=end; - } - } else - {// unknown - PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: - return -1; - } - SKIP_VALUE(message); - } - - if(packet_db[sd->packet_ver][type].len == -1) - {// send dynamic packet - WFIFOW(fd,2)=TOW(off); - WFIFOSET(fd,off); - } else - {// send static packet - if(off < len) - memset(WFIFOP(fd,off),0,len-off); - WFIFOSET(fd,len); - } - } else { - clif_displaymessage(fd, msg_txt(259)); // Invalid packet - return -1; - } - sprintf (atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) - clif_displaymessage(fd, atcmd_output); - return 0; + {\ + if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ + PARSE_ERROR("Invalid number in:",(p));\ + return -1;\ + }\ + } + //define GET_VALUE + + if (type > 0 && type < MAX_PACKET_DB) { + + if (len) { + // show packet length + sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d + clif_displaymessage(fd, atcmd_output); + return 0; + } + + len=packet_db[sd->packet_ver][type].len; + off=2; + if (len == 0) { + // unknown packet - ERROR + sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x + clif_displaymessage(fd, atcmd_output); + return -1; + } else if (len == -1) { + // dynamic packet + len=SHRT_MAX-4; // maximum length + off=4; + } + WFIFOHEAD(fd, len); + WFIFOW(fd,0)=TOW(type); + + // parse packet contents + SKIP_VALUE(message); + while (*message != 0 && off < len) { + if (ISDIGIT(*message) || *message == '-' || *message == '+') { + // default (byte) + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if (TOUPPER(*message) == 'B') { + // byte + ++message; + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if (TOUPPER(*message) == 'W') { + // word (2 bytes) + ++message; + GET_VALUE(message,num); + WFIFOW(fd,off)=TOW(num); + off+=2; + } else if (TOUPPER(*message) == 'L') { + // long word (4 bytes) + ++message; + GET_VALUE(message,num); + WFIFOL(fd,off)=TOL(num); + off+=4; + } else if (TOUPPER(*message) == 'S') { + // string - escapes are valid + // get string length - num <= 0 means not fixed length (default) + ++message; + if (*message == '"') { + num=0; + } else { + GET_VALUE(message,num); + while (*message != '"') { + // find start of string + if (*message == 0 || ISSPACE(*message)) { + PARSE_ERROR(msg_txt(906),message); // Not a string: + return -1; + } + ++message; + } + } + + // parse string + ++message; + CHECK_EOS(message); + end=(num<=0? 0: min(off+((int)num),len)); + for (; *message != '"' && (off < end || end == 0); ++off) { + if (*message == '\\') { + ++message; + CHECK_EOS(message); + switch (*message) { + case 'a': + num=0x07; + break; // Bell + case 'b': + num=0x08; + break; // Backspace + case 't': + num=0x09; + break; // Horizontal tab + case 'n': + num=0x0A; + break; // Line feed + case 'v': + num=0x0B; + break; // Vertical tab + case 'f': + num=0x0C; + break; // Form feed + case 'r': + num=0x0D; + break; // Carriage return + case 'e': + num=0x1B; + break; // Escape + default: + num=*message; + break; + case 'x': { // Hexadecimal + ++message; + CHECK_EOS(message); + if (!ISXDIGIT(*message)) { + PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: + return -1; + } + num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + if (ISXDIGIT(*message)) { + ++message; + CHECK_EOS(message); + num<<=8; + num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + } + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + continue; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { // Octal + num=*message-'0'; // 1st octal digit + ++message; + CHECK_EOS(message); + if (ISDIGIT(*message) && *message < '8') { + num<<=3; + num+=*message-'0'; // 2nd octal digit + ++message; + CHECK_EOS(message); + if (ISDIGIT(*message) && *message < '8') { + num<<=3; + num+=*message-'0'; // 3rd octal digit + ++message; + CHECK_EOS(message); + } + } + WFIFOB(fd,off)=TOB(num); + continue; + } + } + } else + num=*message; + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + }//for + while (*message != '"') { + // ignore extra characters + ++message; + CHECK_EOS(message); + } + + // terminate the string + if (off < end) { + // fill the rest with 0's + memset(WFIFOP(fd,off),0,end-off); + off=end; + } + } else { + // unknown + PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: + return -1; + } + SKIP_VALUE(message); + } + + if (packet_db[sd->packet_ver][type].len == -1) { + // send dynamic packet + WFIFOW(fd,2)=TOW(off); + WFIFOSET(fd,off); + } else { + // send static packet + if (off < len) + memset(WFIFOP(fd,off),0,len-off); + WFIFOSET(fd,len); + } + } else { + clif_displaymessage(fd, msg_txt(259)); // Invalid packet + return -1; + } + sprintf(atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) + clif_displaymessage(fd, atcmd_output); + return 0; #undef PARSE_ERROR #undef CHECK_EOS #undef SKIP_VALUE @@ -442,53 +454,53 @@ ACMD_FUNC(send) *------------------------------------------*/ ACMD_FUNC(mapmove) { - char map_name[MAP_NAME_LENGTH_EXT]; - unsigned short mapindex; - short x = 0, y = 0; - int m = -1; + char map_name[MAP_NAME_LENGTH_EXT]; + unsigned short mapindex; + short x = 0, y = 0; + int m = -1; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || - (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && - sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { + if (!message || !*message || + (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && + sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { - clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). - return -1; - } + clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). + return -1; + } - mapindex = mapindex_name2id(map_name); - if (mapindex) - m = map_mapindex2mapid(mapindex); + mapindex = mapindex_name2id(map_name); + if (mapindex) + m = map_mapindex2mapid(mapindex); - if (!mapindex) { // m < 0 means on different server! [Kevin] - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if (!mapindex) { // m < 0 means on different server! [Kevin] + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) - { //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } - if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) { + //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } + if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - clif_displaymessage(fd, msg_txt(0)); // Warped. - return 0; + clif_displaymessage(fd, msg_txt(0)); // Warped. + return 0; } /*========================================== @@ -496,29 +508,29 @@ ACMD_FUNC(mapmove) *------------------------------------------*/ ACMD_FUNC(where) { - struct map_session_data* pl_sd; + struct map_session_data *pl_sd; - nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof atcmd_player_name); + nullpo_retr(-1, sd); + memset(atcmd_player_name, '\0', sizeof atcmd_player_name); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). + return -1; + } - pl_sd = map_nick2sd(atcmd_player_name); - if (pl_sd == NULL || - strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || - (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - ) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + pl_sd = map_nick2sd(atcmd_player_name); + if (pl_sd == NULL || + strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || + (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + ) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); + snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -526,44 +538,40 @@ ACMD_FUNC(where) *------------------------------------------*/ ACMD_FUNC(jumpto) { - struct map_session_data *pl_sd = NULL; + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). + return -1; + } - if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) - { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. - return -1; - } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if( pc_isdead(sd) ) - { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if (pc_isdead(sd)) { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s - clif_displaymessage(fd, atcmd_output); + pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -571,36 +579,35 @@ ACMD_FUNC(jumpto) *------------------------------------------*/ ACMD_FUNC(jump) { - short x = 0, y = 0; + short x = 0, y = 0; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - sscanf(message, "%hd %hd", &x, &y); + sscanf(message, "%hd %hd", &x, &y); - if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if( pc_isdead(sd) ) - { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if (pc_isdead(sd)) { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) - { //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } + if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) { + //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } - pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d - clif_displaymessage(fd, atcmd_output); - return 0; + pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d + clif_displaymessage(fd, atcmd_output); + return 0; } /*========================================== @@ -609,101 +616,101 @@ ACMD_FUNC(jump) *------------------------------------------*/ ACMD_FUNC(who) { - struct map_session_data *pl_sd = NULL; - struct s_mapiterator *iter = NULL; - char map_name[MAP_NAME_LENGTH_EXT] = ""; - char player_name[NAME_LENGTH] = ""; - int count = 0; - int level = 0; - StringBuf buf; - /** - * 1 = @who : Player name, [Title], [Party name], [Guild name] - * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job - * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y - */ - int display_type = 1; - int map_id = -1; - - nullpo_retr(-1, sd); - - if (strstr(command, "map") != NULL) { - if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } else { - sscanf(message, "%23s", player_name); - } - - if (strstr(command, "2") != NULL) - display_type = 2; - else if (strstr(command, "3") != NULL) - display_type = 3; - - level = pc_get_group_level(sd); - StringBuf_Init(&buf); - - iter = mapit_getallusers(); - for (pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter)) { - if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level - if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive - || (map_id >= 0 && pl_sd->bl.m != map_id)) - continue; - switch (display_type) { - case 2: { - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, - job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" - break; - } - case 3: { - if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" - break; - } - default: { - struct party_data *p = party_search(pl_sd->status.party_id); - struct guild *g = guild_search(pl_sd->status.guild_id); - - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - if (p != NULL) - StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" - if (g != NULL) - StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" - break; - } - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Clear(&buf); - count++; - } - } - mapit_free(iter); - - if (map_id < 0) { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(28)); // No player found. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. - else - StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. - } else { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. - else - StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - return 0; + struct map_session_data *pl_sd = NULL; + struct s_mapiterator *iter = NULL; + char map_name[MAP_NAME_LENGTH_EXT] = ""; + char player_name[NAME_LENGTH] = ""; + int count = 0; + int level = 0; + StringBuf buf; + /** + * 1 = @who : Player name, [Title], [Party name], [Guild name] + * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job + * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y + */ + int display_type = 1; + int map_id = -1; + + nullpo_retr(-1, sd); + + if (strstr(command, "map") != NULL) { + if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } else { + sscanf(message, "%23s", player_name); + } + + if (strstr(command, "2") != NULL) + display_type = 2; + else if (strstr(command, "3") != NULL) + display_type = 3; + + level = pc_get_group_level(sd); + StringBuf_Init(&buf); + + iter = mapit_getallusers(); + for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { + if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level + if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive + || (map_id >= 0 && pl_sd->bl.m != map_id)) + continue; + switch (display_type) { + case 2: { + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, + job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" + break; + } + case 3: { + if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" + break; + } + default: { + struct party_data *p = party_search(pl_sd->status.party_id); + struct guild *g = guild_search(pl_sd->status.guild_id); + + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + if (p != NULL) + StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" + if (g != NULL) + StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" + break; + } + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Clear(&buf); + count++; + } + } + mapit_free(iter); + + if (map_id < 0) { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(28)); // No player found. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. + else + StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. + } else { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. + else + StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + return 0; } /*========================================== @@ -711,85 +718,83 @@ ACMD_FUNC(who) *------------------------------------------*/ ACMD_FUNC(whogm) { - struct map_session_data* pl_sd; - struct s_mapiterator* iter; - int j, count; - int pl_level, level; - char match_text[CHAT_SIZE_MAX]; - char player_name[NAME_LENGTH]; - struct guild *g; - struct party_data *p; - - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(match_text, '\0', sizeof(match_text)); - memset(player_name, '\0', sizeof(player_name)); - - if (sscanf(message, "%199[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = TOLOWER(match_text[j]); - - count = 0; - level = pc_get_group_level(sd); - - iter = mapit_getallusers(); - for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) - { - pl_level = pc_get_group_level(pl_sd); - if (!pl_level) - continue; - - if (match_text[0]) - { - memcpy(player_name, pl_sd->status.name, NAME_LENGTH); - for (j = 0; player_name[j]; j++) - player_name[j] = TOLOWER(player_name[j]); - // search with no case sensitive - if (strstr(player_name, match_text) == NULL) - continue; - } - if (pl_level > level) { - if (pl_sd->sc.option & OPTION_INVISIBLE) - continue; - sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) - clif_displaymessage(fd, atcmd_output); - count++; - continue; - } - - sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d - pl_sd->status.name, pl_level, - mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); - - sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) - pl_sd->status.base_level, - job_name(pl_sd->status.class_), pl_sd->status.job_level); - clif_displaymessage(fd, atcmd_output); - - p = party_search(pl_sd->status.party_id); - g = guild_search(pl_sd->status.guild_id); - - sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' - p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. - - clif_displaymessage(fd, atcmd_output); - count++; - } - mapit_free(iter); - - if (count == 0) - clif_displaymessage(fd, msg_txt(150)); // No GM found. - else if (count == 1) - clif_displaymessage(fd, msg_txt(151)); // 1 GM found. - else { - sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + struct map_session_data *pl_sd; + struct s_mapiterator *iter; + int j, count; + int pl_level, level; + char match_text[CHAT_SIZE_MAX]; + char player_name[NAME_LENGTH]; + struct guild *g; + struct party_data *p; + + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(match_text, '\0', sizeof(match_text)); + memset(player_name, '\0', sizeof(player_name)); + + if (sscanf(message, "%199[^\n]", match_text) < 1) + strcpy(match_text, ""); + for (j = 0; match_text[j]; j++) + match_text[j] = TOLOWER(match_text[j]); + + count = 0; + level = pc_get_group_level(sd); + + iter = mapit_getallusers(); + for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { + pl_level = pc_get_group_level(pl_sd); + if (!pl_level) + continue; + + if (match_text[0]) { + memcpy(player_name, pl_sd->status.name, NAME_LENGTH); + for (j = 0; player_name[j]; j++) + player_name[j] = TOLOWER(player_name[j]); + // search with no case sensitive + if (strstr(player_name, match_text) == NULL) + continue; + } + if (pl_level > level) { + if (pl_sd->sc.option & OPTION_INVISIBLE) + continue; + sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) + clif_displaymessage(fd, atcmd_output); + count++; + continue; + } + + sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d + pl_sd->status.name, pl_level, + mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); + + sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) + pl_sd->status.base_level, + job_name(pl_sd->status.class_), pl_sd->status.job_level); + clif_displaymessage(fd, atcmd_output); + + p = party_search(pl_sd->status.party_id); + g = guild_search(pl_sd->status.guild_id); + + sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' + p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. + + clif_displaymessage(fd, atcmd_output); + count++; + } + mapit_free(iter); + + if (count == 0) + clif_displaymessage(fd, msg_txt(150)); // No GM found. + else if (count == 1) + clif_displaymessage(fd, msg_txt(151)); // 1 GM found. + else { + sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -797,17 +802,17 @@ ACMD_FUNC(whogm) *------------------------------------------*/ ACMD_FUNC(save) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); - if (sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id, &sd->pd->pet); + pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); + if (sd->status.pet_id > 0 && sd->pd) + intif_save_petdata(sd->status.account_id, &sd->pd->pet); - chrif_save(sd,0); + chrif_save(sd,0); - clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. + clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. - return 0; + return 0; } /*========================================== @@ -815,24 +820,24 @@ ACMD_FUNC(save) *------------------------------------------*/ ACMD_FUNC(load) { - int m; + int m; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - m = map_mapindex2mapid(sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + m = map_mapindex2mapid(sd->status.save_point.map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); - clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); + clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. - return 0; + return 0; } /*========================================== @@ -840,22 +845,22 @@ ACMD_FUNC(load) *------------------------------------------*/ ACMD_FUNC(speed) { - int speed; + int speed; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &speed) < 1) { - sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &speed) < 1) { + sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). + clif_displaymessage(fd, atcmd_output); + return -1; + } - sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); - status_calc_bl(&sd->bl, SCB_SPEED); - clif_displaymessage(fd, msg_txt(8)); // Speed changed. - return 0; + sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); + status_calc_bl(&sd->bl, SCB_SPEED); + clif_displaymessage(fd, msg_txt(8)); // Speed changed. + return 0; } /*========================================== @@ -863,20 +868,20 @@ ACMD_FUNC(speed) *------------------------------------------*/ ACMD_FUNC(storage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) + return -1; - if (storage_storageopen(sd) == 1) - { //Already open. - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (storage_storageopen(sd) == 1) { + //Already open. + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - clif_displaymessage(fd, msg_txt(919)); // Storage opened. + clif_displaymessage(fd, msg_txt(919)); // Storage opened. - return 0; + return 0; } @@ -885,29 +890,29 @@ ACMD_FUNC(storage) *------------------------------------------*/ ACMD_FUNC(guildstorage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!sd->status.guild_id) { - clif_displaymessage(fd, msg_txt(252)); - return -1; - } + if (!sd->status.guild_id) { + clif_displaymessage(fd, msg_txt(252)); + return -1; + } - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) + return -1; - if (sd->state.storage_flag == 1) { - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (sd->state.storage_flag == 1) { + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - if (sd->state.storage_flag == 2) { - clif_displaymessage(fd, msg_txt(251)); - return -1; - } + if (sd->state.storage_flag == 2) { + clif_displaymessage(fd, msg_txt(251)); + return -1; + } - storage_guild_storageopen(sd); - clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. - return 0; + storage_guild_storageopen(sd); + clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. + return 0; } /*========================================== @@ -915,34 +920,34 @@ ACMD_FUNC(guildstorage) *------------------------------------------*/ ACMD_FUNC(option) { - int param1 = 0, param2 = 0, param3 = 0; - nullpo_retr(-1, sd); + int param1 = 0, param2 = 0, param3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) - {// failed to match the parameters so inform the user of the options - const char* text = NULL; + if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) { + // failed to match the parameters so inform the user of the options + const char *text = NULL; - // attempt to find the setting information for this command - text = atcommand_help_string( command ); + // attempt to find the setting information for this command + text = atcommand_help_string(command); - // notify the user of the requirement to enter an option - clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. + // notify the user of the requirement to enter an option + clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. - if( text ) - {// send the help text associated with this command - clif_displaymessage( fd, text ); - } + if (text) { + // send the help text associated with this command + clif_displaymessage(fd, text); + } - return -1; - } + return -1; + } - sd->sc.opt1 = param1; - sd->sc.opt2 = param2; - pc_setoption(sd, param3); + sd->sc.opt1 = param1; + sd->sc.opt2 = param2; + pc_setoption(sd, param3); - clif_displaymessage(fd, msg_txt(9)); // Options changed. + clif_displaymessage(fd, msg_txt(9)); // Options changed. - return 0; + return 0; } /*========================================== @@ -950,41 +955,41 @@ ACMD_FUNC(option) *------------------------------------------*/ ACMD_FUNC(hide) { - nullpo_retr(-1, sd); - if (sd->sc.option & OPTION_INVISIBLE) { - sd->sc.option &= ~OPTION_INVISIBLE; - if (sd->disguise) - status_set_viewdata(&sd->bl, sd->disguise); - else - status_set_viewdata(&sd->bl, sd->status.class_); - clif_displaymessage(fd, msg_txt(10)); // Invisible: Off + nullpo_retr(-1, sd); + if (sd->sc.option & OPTION_INVISIBLE) { + sd->sc.option &= ~OPTION_INVISIBLE; + if (sd->disguise) + status_set_viewdata(&sd->bl, sd->disguise); + else + status_set_viewdata(&sd->bl, sd->status.class_); + clif_displaymessage(fd, msg_txt(10)); // Invisible: Off - // increment the number of pvp players on the map - map[sd->bl.m].users_pvp++; + // increment the number of pvp players on the map + map[sd->bl.m].users_pvp++; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank ) - {// register the player for ranking calculations - sd->pvp_timer = add_timer( gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0 ); - } - //bugreport:2266 - map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); - } else { - sd->sc.option |= OPTION_INVISIBLE; - sd->vd.class_ = INVISIBLE_CLASS; - clif_displaymessage(fd, msg_txt(11)); // Invisible: On + if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank) { + // register the player for ranking calculations + sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); + } + //bugreport:2266 + map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); + } else { + sd->sc.option |= OPTION_INVISIBLE; + sd->vd.class_ = INVISIBLE_CLASS; + clif_displaymessage(fd, msg_txt(11)); // Invisible: On - // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + // decrement the number of pvp players on the map + map[sd->bl.m].users_pvp--; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) - {// unregister the player for ranking - delete_timer( sd->pvp_timer, pc_calc_pvprank_timer ); - sd->pvp_timer = INVALID_TIMER; - } - } - clif_changeoption(&sd->bl); + if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER) { + // unregister the player for ranking + delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); + sd->pvp_timer = INVALID_TIMER; + } + } + clif_changeoption(&sd->bl); - return 0; + return 0; } /*========================================== @@ -992,183 +997,185 @@ ACMD_FUNC(hide) *------------------------------------------*/ ACMD_FUNC(jobchange) { - //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage] - int job = 0, upper = 0; - const char* text; - nullpo_retr(-1, sd); - - if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) - { - int i, found = 0; - const struct { char name[24]; int id; } jobs[] = { - { "novice", 0 }, - { "swordman", 1 }, - { "swordsman", 1 }, - { "magician", 2 }, - { "mage", 2 }, - { "archer", 3 }, - { "acolyte", 4 }, - { "merchant", 5 }, - { "thief", 6 }, - { "knight", 7 }, - { "priest", 8 }, - { "priestess", 8 }, - { "wizard", 9 }, - { "blacksmith", 10 }, - { "hunter", 11 }, - { "assassin", 12 }, - { "crusader", 14 }, - { "monk", 15 }, - { "sage", 16 }, - { "rogue", 17 }, - { "alchemist", 18 }, - { "bard", 19 }, - { "dancer", 20 }, - { "super novice", 23 }, - { "supernovice", 23 }, - { "gunslinger", 24 }, - { "gunner", 24 }, - { "ninja", 25 }, - { "novice high", 4001 }, - { "high novice", 4001 }, - { "swordman high", 4002 }, - { "swordsman high", 4002 }, - { "magician high", 4003 }, - { "mage high", 4003 }, - { "archer high", 4004 }, - { "acolyte high", 4005 }, - { "merchant high", 4006 }, - { "thief high", 4007 }, - { "lord knight", 4008 }, - { "high priest", 4009 }, - { "high priestess", 4009 }, - { "high wizard", 4010 }, - { "whitesmith", 4011 }, - { "sniper", 4012 }, - { "assassin cross", 4013 }, - { "paladin", 4015 }, - { "champion", 4016 }, - { "professor", 4017 }, - { "stalker", 4018 }, - { "creator", 4019 }, - { "clown", 4020 }, - { "gypsy", 4021 }, - { "baby novice", 4023 }, - { "baby swordman", 4024 }, - { "baby swordsman", 4024 }, - { "baby magician", 4025 }, - { "baby mage", 4025 }, - { "baby archer", 4026 }, - { "baby acolyte", 4027 }, - { "baby merchant", 4028 }, - { "baby thief", 4029 }, - { "baby knight", 4030 }, - { "baby priest", 4031 }, - { "baby priestess", 4031 }, - { "baby wizard", 4032 }, - { "baby blacksmith",4033 }, - { "baby hunter", 4034 }, - { "baby assassin", 4035 }, - { "baby crusader", 4037 }, - { "baby monk", 4038 }, - { "baby sage", 4039 }, - { "baby rogue", 4040 }, - { "baby alchemist", 4041 }, - { "baby bard", 4042 }, - { "baby dancer", 4043 }, - { "super baby", 4045 }, - { "taekwon", 4046 }, - { "taekwon boy", 4046 }, - { "taekwon girl", 4046 }, - { "star gladiator", 4047 }, - { "soul linker", 4049 }, - { "gangsi", 4050 }, - { "bongun", 4050 }, - { "munak", 4050 }, - { "death knight", 4051 }, - { "dark collector", 4052 }, - { "rune knight", 4054 }, - { "warlock", 4055 }, - { "ranger", 4056 }, - { "arch bishop", 4057 }, - { "mechanic", 4058 }, - { "guillotine", 4059 }, - { "rune knight2", 4060 }, - { "warlock2", 4061 }, - { "ranger2", 4062 }, - { "arch bishop2", 4063 }, - { "mechanic2", 4064 }, - { "guillotine2", 4065 }, - { "royal guard", 4066 }, - { "sorcerer", 4067 }, - { "minstrel", 4068 }, - { "wanderer", 4069 }, - { "sura", 4070 }, - { "genetic", 4071 }, - { "shadow chaser", 4072 }, - { "royal guard2", 4073 }, - { "sorcerer2", 4074 }, - { "minstrel2", 4075 }, - { "wanderer2", 4076 }, - { "sura2", 4077 }, - { "genetic2", 4078 }, - { "shadow chaser2", 4079 }, - { "baby rune", 4096 }, - { "baby warlock", 4097 }, - { "baby ranger", 4098 }, - { "baby bishop", 4099 }, - { "baby mechanic", 4100 }, - { "baby cross", 4101 }, - { "baby guard", 4102 }, - { "baby sorcerer", 4103 }, - { "baby minstrel", 4104 }, - { "baby wanderer", 4105 }, - { "baby sura", 4106 }, - { "baby genetic", 4107 }, - { "baby chaser", 4108 }, - { "super novice e", 4190 }, - { "super baby e", 4191 }, - { "kagerou", 4211 }, - { "oboro", 4212 }, - }; - - for (i=0; i < ARRAYLENGTH(jobs); i++) { - if (strncmpi(message, jobs[i].name, 16) == 0) { - job = jobs[i].id; - upper = 0; - found = 1; - break; - } - } - - if (!found) { - text = atcommand_help_string(command); - if (text) clif_displaymessage(fd, text); - return -1; - } - } - - if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048 - || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) - ) // Deny direct transformation into dummy jobs - {clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." - return 0;} - - if (pcdb_checkid(job)) - { - if (pc_jobchange(sd, job, upper) == 0) - clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. - else { - clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. - return -1; - } - } else { - text = atcommand_help_string(command); - if (text) clif_displaymessage(fd, text); - return -1; - } - - return 0; + //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage] + int job = 0, upper = 0; + const char *text; + nullpo_retr(-1, sd); + + if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { + int i, found = 0; + const struct { + char name[24]; + int id; + } jobs[] = { + { "novice", 0 }, + { "swordman", 1 }, + { "swordsman", 1 }, + { "magician", 2 }, + { "mage", 2 }, + { "archer", 3 }, + { "acolyte", 4 }, + { "merchant", 5 }, + { "thief", 6 }, + { "knight", 7 }, + { "priest", 8 }, + { "priestess", 8 }, + { "wizard", 9 }, + { "blacksmith", 10 }, + { "hunter", 11 }, + { "assassin", 12 }, + { "crusader", 14 }, + { "monk", 15 }, + { "sage", 16 }, + { "rogue", 17 }, + { "alchemist", 18 }, + { "bard", 19 }, + { "dancer", 20 }, + { "super novice", 23 }, + { "supernovice", 23 }, + { "gunslinger", 24 }, + { "gunner", 24 }, + { "ninja", 25 }, + { "novice high", 4001 }, + { "high novice", 4001 }, + { "swordman high", 4002 }, + { "swordsman high", 4002 }, + { "magician high", 4003 }, + { "mage high", 4003 }, + { "archer high", 4004 }, + { "acolyte high", 4005 }, + { "merchant high", 4006 }, + { "thief high", 4007 }, + { "lord knight", 4008 }, + { "high priest", 4009 }, + { "high priestess", 4009 }, + { "high wizard", 4010 }, + { "whitesmith", 4011 }, + { "sniper", 4012 }, + { "assassin cross", 4013 }, + { "paladin", 4015 }, + { "champion", 4016 }, + { "professor", 4017 }, + { "stalker", 4018 }, + { "creator", 4019 }, + { "clown", 4020 }, + { "gypsy", 4021 }, + { "baby novice", 4023 }, + { "baby swordman", 4024 }, + { "baby swordsman", 4024 }, + { "baby magician", 4025 }, + { "baby mage", 4025 }, + { "baby archer", 4026 }, + { "baby acolyte", 4027 }, + { "baby merchant", 4028 }, + { "baby thief", 4029 }, + { "baby knight", 4030 }, + { "baby priest", 4031 }, + { "baby priestess", 4031 }, + { "baby wizard", 4032 }, + { "baby blacksmith",4033 }, + { "baby hunter", 4034 }, + { "baby assassin", 4035 }, + { "baby crusader", 4037 }, + { "baby monk", 4038 }, + { "baby sage", 4039 }, + { "baby rogue", 4040 }, + { "baby alchemist", 4041 }, + { "baby bard", 4042 }, + { "baby dancer", 4043 }, + { "super baby", 4045 }, + { "taekwon", 4046 }, + { "taekwon boy", 4046 }, + { "taekwon girl", 4046 }, + { "star gladiator", 4047 }, + { "soul linker", 4049 }, + { "gangsi", 4050 }, + { "bongun", 4050 }, + { "munak", 4050 }, + { "death knight", 4051 }, + { "dark collector", 4052 }, + { "rune knight", 4054 }, + { "warlock", 4055 }, + { "ranger", 4056 }, + { "arch bishop", 4057 }, + { "mechanic", 4058 }, + { "guillotine", 4059 }, + { "rune knight2", 4060 }, + { "warlock2", 4061 }, + { "ranger2", 4062 }, + { "arch bishop2", 4063 }, + { "mechanic2", 4064 }, + { "guillotine2", 4065 }, + { "royal guard", 4066 }, + { "sorcerer", 4067 }, + { "minstrel", 4068 }, + { "wanderer", 4069 }, + { "sura", 4070 }, + { "genetic", 4071 }, + { "shadow chaser", 4072 }, + { "royal guard2", 4073 }, + { "sorcerer2", 4074 }, + { "minstrel2", 4075 }, + { "wanderer2", 4076 }, + { "sura2", 4077 }, + { "genetic2", 4078 }, + { "shadow chaser2", 4079 }, + { "baby rune", 4096 }, + { "baby warlock", 4097 }, + { "baby ranger", 4098 }, + { "baby bishop", 4099 }, + { "baby mechanic", 4100 }, + { "baby cross", 4101 }, + { "baby guard", 4102 }, + { "baby sorcerer", 4103 }, + { "baby minstrel", 4104 }, + { "baby wanderer", 4105 }, + { "baby sura", 4106 }, + { "baby genetic", 4107 }, + { "baby chaser", 4108 }, + { "super novice e", 4190 }, + { "super baby e", 4191 }, + { "kagerou", 4211 }, + { "oboro", 4212 }, + }; + + for (i=0; i < ARRAYLENGTH(jobs); i++) { + if (strncmpi(message, jobs[i].name, 16) == 0) { + job = jobs[i].id; + upper = 0; + found = 1; + break; + } + } + + if (!found) { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + } + + if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048 + || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) + ) { // Deny direct transformation into dummy jobs + clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." + return 0; + } + + if (pcdb_checkid(job)) { + if (pc_jobchange(sd, job, upper) == 0) + clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. + else { + clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. + return -1; + } + } else { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + + return 0; } /*========================================== @@ -1176,12 +1183,12 @@ ACMD_FUNC(jobchange) *------------------------------------------*/ ACMD_FUNC(kill) { - nullpo_retr(-1, sd); - status_kill(&sd->bl); - clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. - if (fd != sd->fd) - clif_displaymessage(fd, msg_txt(14)); // Character killed. - return 0; + nullpo_retr(-1, sd); + status_kill(&sd->bl); + clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. + if (fd != sd->fd) + clif_displaymessage(fd, msg_txt(14)); // Character killed. + return 0; } /*========================================== @@ -1189,15 +1196,14 @@ ACMD_FUNC(kill) *------------------------------------------*/ ACMD_FUNC(alive) { - nullpo_retr(-1, sd); - if (!status_revive(&sd->bl, 100, 100)) - { - clif_displaymessage(fd, msg_txt(667)); - return -1; - } - clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); - clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! - return 0; + nullpo_retr(-1, sd); + if (!status_revive(&sd->bl, 100, 100)) { + clif_displaymessage(fd, msg_txt(667)); + return -1; + } + clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); + clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! + return 0; } /*========================================== @@ -1205,35 +1211,35 @@ ACMD_FUNC(alive) *------------------------------------------*/ ACMD_FUNC(kami) { - unsigned long color=0; - nullpo_retr(-1, sd); + unsigned long color=0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if(*(command + 5) != 'c' && *(command + 5) != 'C') { - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). - return -1; - } + if (*(command + 5) != 'c' && *(command + 5) != 'C') { + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). + return -1; + } - sscanf(message, "%199[^\n]", atcmd_output); - if (strstr(command, "l") != NULL) - clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); - else - intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); - } else { - if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { - clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). - return -1; - } + sscanf(message, "%199[^\n]", atcmd_output); + if (strstr(command, "l") != NULL) + clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); + else + intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); + } else { + if (!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { + clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). + return -1; + } - if(color > 0xFFFFFF) { - clif_displaymessage(fd, msg_txt(982)); // Invalid color. - return -1; - } - intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); - } - return 0; + if (color > 0xFFFFFF) { + clif_displaymessage(fd, msg_txt(982)); // Invalid color. + return -1; + } + intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); + } + return 0; } /*========================================== @@ -1241,57 +1247,57 @@ ACMD_FUNC(kami) *------------------------------------------*/ ACMD_FUNC(heal) { - int hp = 0, sp = 0; // [Valaris] thanks to fov - nullpo_retr(-1, sd); - - sscanf(message, "%d %d", &hp, &sp); - - // some overflow checks - if( hp == INT_MIN ) hp++; - if( sp == INT_MIN ) sp++; - - if ( hp == 0 && sp == 0 ) { - if (!status_percent_heal(&sd->bl, 100, 100)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if ( hp > 0 && sp >= 0 ) { - if(!status_heal(&sd->bl, hp, sp, 0)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if ( hp < 0 && sp <= 0 ) { - status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; - } - - //Opposing signs. - if ( hp ) { - if (hp > 0) - status_heal(&sd->bl, hp, 0, 0); - else { - status_damage(NULL, &sd->bl, -hp, 0, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - } - } - - if ( sp ) { - if (sp > 0) - status_heal(&sd->bl, 0, sp, 0); - else - status_damage(NULL, &sd->bl, 0, -sp, 0, 0); - } - - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; + int hp = 0, sp = 0; // [Valaris] thanks to fov + nullpo_retr(-1, sd); + + sscanf(message, "%d %d", &hp, &sp); + + // some overflow checks + if (hp == INT_MIN) hp++; + if (sp == INT_MIN) sp++; + + if (hp == 0 && sp == 0) { + if (!status_percent_heal(&sd->bl, 100, 100)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if (hp > 0 && sp >= 0) { + if (!status_heal(&sd->bl, hp, sp, 0)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if (hp < 0 && sp <= 0) { + status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; + } + + //Opposing signs. + if (hp) { + if (hp > 0) + status_heal(&sd->bl, hp, 0, 0); + else { + status_damage(NULL, &sd->bl, -hp, 0, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + } + } + + if (sp) { + if (sp > 0) + status_heal(&sd->bl, 0, sp, 0); + else + status_damage(NULL, &sd->bl, 0, -sp, 0, 0); + } + + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; } /*========================================== @@ -1299,54 +1305,53 @@ ACMD_FUNC(heal) *------------------------------------------*/ ACMD_FUNC(item) { - char item_name[100]; - int number = 0, item_id, flag = 0; - struct item item_tmp; - struct item_data *item_data; - int get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && - sscanf(message, "%99s %d", item_name, &number) < 1 - )) { - clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). - return -1; - } - - if (number <= 0) - number = 1; - - if ((item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL) - { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - item_id = item_data->nameid; - get_count = number; - //Check if it's stackable. - if (!itemdb_isstackable2(item_data)) - get_count = 1; - - for (i = 0; i < number; i += get_count) { - // if not pet egg - if (!pet_create_egg(sd, item_id)) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = 1; - - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - return 0; + char item_name[100]; + int number = 0, item_id, flag = 0; + struct item item_tmp; + struct item_data *item_data; + int get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && + sscanf(message, "%99s %d", item_name, &number) < 1 + )) { + clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). + return -1; + } + + if (number <= 0) + number = 1; + + if ((item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL) { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + item_id = item_data->nameid; + get_count = number; + //Check if it's stackable. + if (!itemdb_isstackable2(item_data)) + get_count = 1; + + for (i = 0; i < number; i += get_count) { + // if not pet egg + if (!pet_create_egg(sd, item_id)) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = 1; + + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + return 0; } /*========================================== @@ -1354,76 +1359,76 @@ ACMD_FUNC(item) *------------------------------------------*/ ACMD_FUNC(item2) { - struct item item_tmp; - struct item_data *item_data; - char item_name[100]; - int item_id, number = 0; - int identify = 0, refine = 0, attr = 0; - int c1 = 0, c2 = 0, c3 = 0, c4 = 0; - int flag = 0; - int loop, get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && - sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 - )) { - clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 - clif_displaymessage(fd, msg_txt(985)); // ). - return -1; - } - - if (number <= 0) - number = 1; - - item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) - item_id = item_data->nameid; - - if (item_id > 500) { - loop = 1; - get_count = number; - if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || - item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { - loop = number; - get_count = 1; - if (item_data->type == IT_PETEGG) { - identify = 1; - refine = 0; - } - if (item_data->type == IT_PETARMOR) - refine = 0; - if (refine > MAX_REFINE) - refine = MAX_REFINE; - } else { - identify = 1; - refine = attr = 0; - } - for (i = 0; i < loop; i++) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = identify; - item_tmp.refine = refine; - item_tmp.attribute = attr; - item_tmp.card[0] = c1; - item_tmp.card[1] = c2; - item_tmp.card[2] = c3; - item_tmp.card[3] = c4; - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - } else { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - return 0; + struct item item_tmp; + struct item_data *item_data; + char item_name[100]; + int item_id, number = 0; + int identify = 0, refine = 0, attr = 0; + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + int flag = 0; + int loop, get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && + sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 + )) { + clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 + clif_displaymessage(fd, msg_txt(985)); // ). + return -1; + } + + if (number <= 0) + number = 1; + + item_id = 0; + if ((item_data = itemdb_searchname(item_name)) != NULL || + (item_data = itemdb_exists(atoi(item_name))) != NULL) + item_id = item_data->nameid; + + if (item_id > 500) { + loop = 1; + get_count = number; + if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || + item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { + loop = number; + get_count = 1; + if (item_data->type == IT_PETEGG) { + identify = 1; + refine = 0; + } + if (item_data->type == IT_PETARMOR) + refine = 0; + if (refine > MAX_REFINE) + refine = MAX_REFINE; + } else { + identify = 1; + refine = attr = 0; + } + for (i = 0; i < loop; i++) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = identify; + item_tmp.refine = refine; + item_tmp.attribute = attr; + item_tmp.card[0] = c1; + item_tmp.card[1] = c2; + item_tmp.card[2] = c3; + item_tmp.card[3] = c4; + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + } else { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + return 0; } /*========================================== @@ -1431,17 +1436,17 @@ ACMD_FUNC(item2) *------------------------------------------*/ ACMD_FUNC(itemreset) { - int i; - nullpo_retr(-1, sd); + int i; + nullpo_retr(-1, sd); - for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { - pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); - } - } - clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. + for (i = 0; i < MAX_INVENTORY; i++) { + if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { + pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); + } + } + clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. - return 0; + return 0; } /*========================================== @@ -1449,59 +1454,59 @@ ACMD_FUNC(itemreset) *------------------------------------------*/ ACMD_FUNC(baselevelup) { - int level=0, i=0, status_point=0; - nullpo_retr(-1, sd); - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). - return -1; - } - - if (level > 0) { - if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris - clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. - return -1; - } // End Addition - if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow - level = pc_maxbaselv(sd) - sd->status.base_level; - for (i = 0; i < level; i++) - status_point += pc_gets_status_point(sd->status.base_level + i); - - sd->status.status_point += status_point; - sd->status.base_level += (unsigned int)level; - status_percent_heal(&sd->bl, 100, 100); - clif_misceffect(&sd->bl, 0); - clif_displaymessage(fd, msg_txt(21)); // Base level raised. - } else { - if (sd->status.base_level == 1) { - clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. - return -1; - } - level*=-1; - if ((unsigned int)level >= sd->status.base_level) - level = sd->status.base_level-1; - for (i = 0; i > -level; i--) - status_point += pc_gets_status_point(sd->status.base_level + i - 1); - if (sd->status.status_point < status_point) - pc_resetstate(sd); - if (sd->status.status_point < status_point) - sd->status.status_point = 0; - else - sd->status.status_point -= status_point; - sd->status.base_level -= (unsigned int)level; - clif_displaymessage(fd, msg_txt(22)); // Base level lowered. - } - sd->status.base_exp = 0; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_updatestatus(sd, SP_BASELEVEL); - clif_updatestatus(sd, SP_BASEEXP); - clif_updatestatus(sd, SP_NEXTBASEEXP); - status_calc_pc(sd, 0); - pc_baselevelchanged(sd); - if(sd->status.party_id) - party_send_levelup(sd); - return 0; + int level=0, i=0, status_point=0; + nullpo_retr(-1, sd); + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). + return -1; + } + + if (level > 0) { + if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris + clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. + return -1; + } // End Addition + if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow + level = pc_maxbaselv(sd) - sd->status.base_level; + for (i = 0; i < level; i++) + status_point += pc_gets_status_point(sd->status.base_level + i); + + sd->status.status_point += status_point; + sd->status.base_level += (unsigned int)level; + status_percent_heal(&sd->bl, 100, 100); + clif_misceffect(&sd->bl, 0); + clif_displaymessage(fd, msg_txt(21)); // Base level raised. + } else { + if (sd->status.base_level == 1) { + clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. + return -1; + } + level*=-1; + if ((unsigned int)level >= sd->status.base_level) + level = sd->status.base_level-1; + for (i = 0; i > -level; i--) + status_point += pc_gets_status_point(sd->status.base_level + i - 1); + if (sd->status.status_point < status_point) + pc_resetstate(sd); + if (sd->status.status_point < status_point) + sd->status.status_point = 0; + else + sd->status.status_point -= status_point; + sd->status.base_level -= (unsigned int)level; + clif_displaymessage(fd, msg_txt(22)); // Base level lowered. + } + sd->status.base_exp = 0; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_updatestatus(sd, SP_BASELEVEL); + clif_updatestatus(sd, SP_BASEEXP); + clif_updatestatus(sd, SP_NEXTBASEEXP); + status_calc_pc(sd, 0); + pc_baselevelchanged(sd); + if (sd->status.party_id) + party_send_levelup(sd); + return 0; } /*========================================== @@ -1509,51 +1514,51 @@ ACMD_FUNC(baselevelup) *------------------------------------------*/ ACMD_FUNC(joblevelup) { - int level=0; - nullpo_retr(-1, sd); - - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). - return -1; - } - if (level > 0) { - if (sd->status.job_level >= pc_maxjoblv(sd)) { - clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. - return -1; - } - if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow - level = pc_maxjoblv(sd) - sd->status.job_level; - sd->status.job_level += (unsigned int)level; - sd->status.skill_point += level; - clif_misceffect(&sd->bl, 1); - clif_displaymessage(fd, msg_txt(24)); // Job level raised. - } else { - if (sd->status.job_level == 1) { - clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. - return -1; - } - level *=-1; - if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow - level = sd->status.job_level-1; - sd->status.job_level -= (unsigned int)level; - if (sd->status.skill_point < level) - pc_resetskill(sd,0); //Reset skills since we need to substract more points. - if (sd->status.skill_point < level) - sd->status.skill_point = 0; - else - sd->status.skill_point -= level; - clif_displaymessage(fd, msg_txt(25)); // Job level lowered. - } - sd->status.job_exp = 0; - clif_updatestatus(sd, SP_JOBLEVEL); - clif_updatestatus(sd, SP_JOBEXP); - clif_updatestatus(sd, SP_NEXTJOBEXP); - clif_updatestatus(sd, SP_SKILLPOINT); - status_calc_pc(sd, 0); - - return 0; + int level=0; + nullpo_retr(-1, sd); + + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). + return -1; + } + if (level > 0) { + if (sd->status.job_level >= pc_maxjoblv(sd)) { + clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. + return -1; + } + if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow + level = pc_maxjoblv(sd) - sd->status.job_level; + sd->status.job_level += (unsigned int)level; + sd->status.skill_point += level; + clif_misceffect(&sd->bl, 1); + clif_displaymessage(fd, msg_txt(24)); // Job level raised. + } else { + if (sd->status.job_level == 1) { + clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. + return -1; + } + level *=-1; + if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow + level = sd->status.job_level-1; + sd->status.job_level -= (unsigned int)level; + if (sd->status.skill_point < level) + pc_resetskill(sd,0); //Reset skills since we need to substract more points. + if (sd->status.skill_point < level) + sd->status.skill_point = 0; + else + sd->status.skill_point -= level; + clif_displaymessage(fd, msg_txt(25)); // Job level lowered. + } + sd->status.job_exp = 0; + clif_updatestatus(sd, SP_JOBLEVEL); + clif_updatestatus(sd, SP_JOBEXP); + clif_updatestatus(sd, SP_NEXTJOBEXP); + clif_updatestatus(sd, SP_SKILLPOINT); + status_calc_pc(sd, 0); + + return 0; } /*========================================== @@ -1561,116 +1566,116 @@ ACMD_FUNC(joblevelup) *------------------------------------------*/ ACMD_FUNC(help) { - config_setting_t *help; - const char *text = NULL; - const char *command_name = NULL; - char *default_command = "help"; - - nullpo_retr(-1, sd); - - help = config_lookup(&atcommand_config, "help"); - if (help == NULL) { - clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." - return -1; - } - - if (!message || !*message) { - command_name = default_command; // If no command_name specified, display help for @help. - } else { - if (*message == atcommand_symbol || *message == charcommand_symbol) - ++message; - command_name = atcommand_checkalias(message); - } - - if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { - sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - if (!config_setting_lookup_string(help, command_name, &text)) { - sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: - clif_displaymessage(fd, atcmd_output); - - { // Display aliases - DBIterator* iter; - AtCommandInfo *command_info; - AliasInfo *alias_info = NULL; - StringBuf buf; - bool has_aliases = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: - command_info = get_atcommandinfo_byname(command_name); - iter = db_iterator(atcommand_alias_db); - for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { - if (alias_info->command == command_info) { - StringBuf_Printf(&buf, " %s", alias_info->alias); - has_aliases = true; - } - } - dbi_destroy(iter); - if (has_aliases) - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - } - - // Display help contents - clif_displaymessage(fd, text); - return 0; + config_setting_t *help; + const char *text = NULL; + const char *command_name = NULL; + char *default_command = "help"; + + nullpo_retr(-1, sd); + + help = config_lookup(&atcommand_config, "help"); + if (help == NULL) { + clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." + return -1; + } + + if (!message || !*message) { + command_name = default_command; // If no command_name specified, display help for @help. + } else { + if (*message == atcommand_symbol || *message == charcommand_symbol) + ++message; + command_name = atcommand_checkalias(message); + } + + if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { + sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + if (!config_setting_lookup_string(help, command_name, &text)) { + sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: + clif_displaymessage(fd, atcmd_output); + + { + // Display aliases + DBIterator *iter; + AtCommandInfo *command_info; + AliasInfo *alias_info = NULL; + StringBuf buf; + bool has_aliases = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: + command_info = get_atcommandinfo_byname(command_name); + iter = db_iterator(atcommand_alias_db); + for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { + if (alias_info->command == command_info) { + StringBuf_Printf(&buf, " %s", alias_info->alias); + has_aliases = true; + } + } + dbi_destroy(iter); + if (has_aliases) + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + } + + // Display help contents + clif_displaymessage(fd, text); + return 0; } // helper function, used in foreach calls to stop auto-attack timers // parameter: '0' - everyone, 'id' - only those attacking someone with that id static int atcommand_stopattack(struct block_list *bl,va_list ap) { - struct unit_data *ud = unit_bl2ud(bl); - int id = va_arg(ap, int); - if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) - { - unit_stop_attack(bl); - return 1; - } - return 0; + struct unit_data *ud = unit_bl2ud(bl); + int id = va_arg(ap, int); + if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) { + unit_stop_attack(bl); + return 1; + } + return 0; } /*========================================== * *------------------------------------------*/ static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) { - TBL_PC* sd = (TBL_PC*)bl; - clif_pvpset(sd, 0, 0, 2); - if (sd->pvp_timer != INVALID_TIMER) { - delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = INVALID_TIMER; - } - return 0; + TBL_PC *sd = (TBL_PC *)bl; + clif_pvpset(sd, 0, 0, 2); + if (sd->pvp_timer != INVALID_TIMER) { + delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); + sd->pvp_timer = INVALID_TIMER; + } + return 0; } ACMD_FUNC(pvpoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. - return -1; - } + if (!map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. + return -1; + } - map[sd->bl.m].flag.pvp = 0; + map[sd->bl.m].flag.pvp = 0; - if (!battle_config.pk_mode) - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(31)); // PvP: Off. - return 0; + if (!battle_config.pk_mode) + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(31)); // PvP: Off. + return 0; } /*========================================== @@ -1678,38 +1683,38 @@ ACMD_FUNC(pvpoff) *------------------------------------------*/ static int atcommand_pvpon_sub(struct block_list *bl,va_list ap) { - TBL_PC* sd = (TBL_PC*)bl; - if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); - sd->pvp_rank = 0; - sd->pvp_lastusers = 0; - sd->pvp_point = 5; - sd->pvp_won = 0; - sd->pvp_lost = 0; - } - return 0; + TBL_PC *sd = (TBL_PC *)bl; + if (sd->pvp_timer == INVALID_TIMER) { + sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); + sd->pvp_rank = 0; + sd->pvp_lastusers = 0; + sd->pvp_point = 5; + sd->pvp_won = 0; + sd->pvp_lost = 0; + } + return 0; } ACMD_FUNC(pvpon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(161)); // PvP is already On. - return -1; - } + if (map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(161)); // PvP is already On. + return -1; + } - map[sd->bl.m].flag.pvp = 1; + map[sd->bl.m].flag.pvp = 1; - if (!battle_config.pk_mode) - {// display pvp circle and rank - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); - map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); - } + if (!battle_config.pk_mode) { + // display pvp circle and rank + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); + map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); + } - clif_displaymessage(fd, msg_txt(32)); // PvP: On. + clif_displaymessage(fd, msg_txt(32)); // PvP: On. - return 0; + return 0; } /*========================================== @@ -1717,19 +1722,19 @@ ACMD_FUNC(pvpon) *------------------------------------------*/ ACMD_FUNC(gvgoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. - return -1; - } + if (!map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. + return -1; + } - map[sd->bl.m].flag.gvg = 0; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(33)); // GvG: Off. + map[sd->bl.m].flag.gvg = 0; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(33)); // GvG: Off. - return 0; + return 0; } /*========================================== @@ -1737,18 +1742,18 @@ ACMD_FUNC(gvgoff) *------------------------------------------*/ ACMD_FUNC(gvgon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(163)); // GvG is already On. - return -1; - } + if (map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(163)); // GvG is already On. + return -1; + } - map[sd->bl.m].flag.gvg = 1; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); - clif_displaymessage(fd, msg_txt(34)); // GvG: On. + map[sd->bl.m].flag.gvg = 1; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); + clif_displaymessage(fd, msg_txt(34)); // GvG: On. - return 0; + return 0; } /*========================================== @@ -1756,31 +1761,31 @@ ACMD_FUNC(gvgon) *------------------------------------------*/ ACMD_FUNC(model) { - int hair_style = 0, hair_color = 0, cloth_color = 0; - nullpo_retr(-1, sd); + int hair_style = 0, hair_color = 0, cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). - MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). + MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && - hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && - cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_HAIR, hair_style); - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && + hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && + cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_HAIR, hair_style); + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1788,26 +1793,26 @@ ACMD_FUNC(model) *------------------------------------------*/ ACMD_FUNC(dye) { - int cloth_color = 0; - nullpo_retr(-1, sd); + int cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1815,26 +1820,26 @@ ACMD_FUNC(dye) *------------------------------------------*/ ACMD_FUNC(hair_style) { - int hair_style = 0; - nullpo_retr(-1, sd); + int hair_style = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { - sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { + sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { - pc_changelook(sd, LOOK_HAIR, hair_style); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { + pc_changelook(sd, LOOK_HAIR, hair_style); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1842,26 +1847,26 @@ ACMD_FUNC(hair_style) *------------------------------------------*/ ACMD_FUNC(hair_color) { - int hair_color = 0; - nullpo_retr(-1, sd); + int hair_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { - sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { + sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1869,199 +1874,198 @@ ACMD_FUNC(hair_color) *------------------------------------------*/ ACMD_FUNC(go) { - int i; - int town; - char map_name[MAP_NAME_LENGTH]; - int m; - - const struct { - char map[MAP_NAME_LENGTH]; - int x, y; - } data[] = { - { MAP_PRONTERA, 156, 191 }, // 0=Prontera - { MAP_MORROC, 156, 93 }, // 1=Morroc - { MAP_GEFFEN, 119, 59 }, // 2=Geffen - { MAP_PAYON, 162, 233 }, // 3=Payon - { MAP_ALBERTA, 192, 147 }, // 4=Alberta + int i; + int town; + char map_name[MAP_NAME_LENGTH]; + int m; + + const struct { + char map[MAP_NAME_LENGTH]; + int x, y; + } data[] = { + { MAP_PRONTERA, 156, 191 }, // 0=Prontera + { MAP_MORROC, 156, 93 }, // 1=Morroc + { MAP_GEFFEN, 119, 59 }, // 2=Geffen + { MAP_PAYON, 162, 233 }, // 3=Payon + { MAP_ALBERTA, 192, 147 }, // 4=Alberta #ifdef RENEWAL - { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) + { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) #else - { MAP_IZLUDE, 128, 114 }, // 5=Izlude + { MAP_IZLUDE, 128, 114 }, // 5=Izlude #endif - { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran - { MAP_LUTIE, 147, 134 }, // 7=Lutie - { MAP_COMODO, 209, 143 }, // 8=Comodo - { MAP_YUNO, 157, 51 }, // 9=Yuno - { MAP_AMATSU, 198, 84 }, // 10=Amatsu - { MAP_GONRYUN, 160, 120 }, // 11=Gonryun - { MAP_UMBALA, 89, 157 }, // 12=Umbala - { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim - { MAP_LOUYANG, 217, 40 }, // 14=Louyang - { MAP_NOVICE, 53, 111 }, // 15=Training Grounds - { MAP_JAIL, 23, 61 }, // 16=Prison - { MAP_JAWAII, 249, 127 }, // 17=Jawaii - { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya - { MAP_EINBROCH, 64, 200 }, // 19=Einbroch - { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen - { MAP_EINBECH, 70, 95 }, // 21=Einbech - { MAP_HUGEL, 96, 145 }, // 22=Hugel - { MAP_RACHEL, 130, 110 }, // 23=Rachel - { MAP_VEINS, 216, 123 }, // 24=Veins - { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia - { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp - { MAP_MANUK, 282, 138 }, // 27=Manuk - { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide - { MAP_BRASILIS, 182, 239 }, // 29=Brasilis - { MAP_DICASTES, 198, 187 }, // 30=El Dicastes - { MAP_MORA, 44, 151 }, // 31=Mora - { MAP_DEWATA, 200, 180 }, // 32=Dewata - { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island - { MAP_MALAYA, 242, 211 }, // 34=Malaya Port - { MAP_ECLAGE, 110, 39 }, // 35=Eclage - }; - - nullpo_retr(-1, sd); - - if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { - clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. - return 0; - } - - memset(map_name, '\0', sizeof(map_name)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - // get the number - town = atoi(message); - - if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) - {// no value matched so send the list of locations - const char* text; - - // attempt to find the text help string - text = atcommand_help_string( command ); - - clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. - - if( text ) - {// send the text to the client - clif_displaymessage( fd, text ); - } - - return -1; - } - - // get possible name of the city - map_name[MAP_NAME_LENGTH-1] = '\0'; - for (i = 0; map_name[i]; i++) - map_name[i] = TOLOWER(map_name[i]); - // try to identify the map name - if (strncmp(map_name, "prontera", 3) == 0) { - town = 0; - } else if (strncmp(map_name, "morocc", 4) == 0 || - strncmp(map_name, "morroc", 4) == 0) { - town = 1; - } else if (strncmp(map_name, "geffen", 3) == 0) { - town = 2; - } else if (strncmp(map_name, "payon", 3) == 0) { - town = 3; - } else if (strncmp(map_name, "alberta", 3) == 0) { - town = 4; - } else if (strncmp(map_name, "izlude", 3) == 0) { - town = 5; - } else if (strncmp(map_name, "aldebaran", 3) == 0) { - town = 6; - } else if (strncmp(map_name, "lutie", 3) == 0 || - strcmp(map_name, "christmas") == 0 || - strncmp(map_name, "xmas", 3) == 0 || - strncmp(map_name, "x-mas", 3) == 0) { - town = 7; - } else if (strncmp(map_name, "comodo", 3) == 0) { - town = 8; - } else if (strncmp(map_name, "juno", 3) == 0 || - strncmp(map_name, "yuno", 3) == 0) { - town = 9; - } else if (strncmp(map_name, "amatsu", 3) == 0) { - town = 10; - } else if (strncmp(map_name, "kunlun", 3) == 0 || - strncmp(map_name, "gonryun", 3) == 0) { - town = 11; - } else if (strncmp(map_name, "umbala", 3) == 0) { - town = 12; - } else if (strncmp(map_name, "niflheim", 3) == 0) { - town = 13; - } else if (strncmp(map_name, "louyang", 3) == 0) { - town = 14; - } else if (strncmp(map_name, "new_1-1", 3) == 0 || - strncmp(map_name, "startpoint", 3) == 0 || - strncmp(map_name, "beginning", 3) == 0) { - town = 15; - } else if (strncmp(map_name, "sec_pri", 3) == 0 || - strncmp(map_name, "prison", 3) == 0 || - strncmp(map_name, "jail", 3) == 0) { - town = 16; - } else if (strncmp(map_name, "jawaii", 3) == 0) { - town = 17; - } else if (strncmp(map_name, "ayothaya", 3) == 0) { - town = 18; - } else if (strncmp(map_name, "einbroch", 5) == 0) { - town = 19; - } else if (strncmp(map_name, "lighthalzen", 3) == 0) { - town = 20; - } else if (strncmp(map_name, "einbech", 5) == 0) { - town = 21; - } else if (strncmp(map_name, "hugel", 3) == 0) { - town = 22; - } else if (strncmp(map_name, "rachel", 3) == 0) { - town = 23; - } else if (strncmp(map_name, "veins", 3) == 0) { - town = 24; - } else if (strncmp(map_name, "moscovia", 3) == 0) { - town = 25; - } else if (strncmp(map_name, "mid_camp", 3) == 0) { - town = 26; - } else if (strncmp(map_name, "manuk", 3) == 0) { - town = 27; - } else if (strncmp(map_name, "splendide", 3) == 0) { - town = 28; - } else if (strncmp(map_name, "brasilis", 3) == 0) { - town = 29; - } else if (strncmp(map_name, "dicastes01", 3) == 0) { - town = 30; - } else if (strcmp(map_name, "mora") == 0) { - town = 31; - } else if (strncmp(map_name, "dewata", 3) == 0) { - town = 32; - } else if (strncmp(map_name, "malangdo", 5) == 0) { - town = 33; - } else if (strncmp(map_name, "malaya", 5) == 0) { - town = 34; - } else if (strncmp(map_name, "eclage", 3) == 0) { - town = 35; - } - - if (town >= 0 && town < ARRAYLENGTH(data)) - { - m = map_mapname2mapid(data[town].map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { - clif_displaymessage(fd, msg_txt(0)); // Warped. - } else { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } - } else { // if you arrive here, you have an error in town variable when reading of names - clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. - return -1; - } - - return 0; + { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran + { MAP_LUTIE, 147, 134 }, // 7=Lutie + { MAP_COMODO, 209, 143 }, // 8=Comodo + { MAP_YUNO, 157, 51 }, // 9=Yuno + { MAP_AMATSU, 198, 84 }, // 10=Amatsu + { MAP_GONRYUN, 160, 120 }, // 11=Gonryun + { MAP_UMBALA, 89, 157 }, // 12=Umbala + { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim + { MAP_LOUYANG, 217, 40 }, // 14=Louyang + { MAP_NOVICE, 53, 111 }, // 15=Training Grounds + { MAP_JAIL, 23, 61 }, // 16=Prison + { MAP_JAWAII, 249, 127 }, // 17=Jawaii + { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya + { MAP_EINBROCH, 64, 200 }, // 19=Einbroch + { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen + { MAP_EINBECH, 70, 95 }, // 21=Einbech + { MAP_HUGEL, 96, 145 }, // 22=Hugel + { MAP_RACHEL, 130, 110 }, // 23=Rachel + { MAP_VEINS, 216, 123 }, // 24=Veins + { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia + { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp + { MAP_MANUK, 282, 138 }, // 27=Manuk + { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide + { MAP_BRASILIS, 182, 239 }, // 29=Brasilis + { MAP_DICASTES, 198, 187 }, // 30=El Dicastes + { MAP_MORA, 44, 151 }, // 31=Mora + { MAP_DEWATA, 200, 180 }, // 32=Dewata + { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island + { MAP_MALAYA, 242, 211 }, // 34=Malaya Port + { MAP_ECLAGE, 110, 39 }, // 35=Eclage + }; + + nullpo_retr(-1, sd); + + if (map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. + return 0; + } + + memset(map_name, '\0', sizeof(map_name)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + // get the number + town = atoi(message); + + if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) { + // no value matched so send the list of locations + const char *text; + + // attempt to find the text help string + text = atcommand_help_string(command); + + clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. + + if (text) { + // send the text to the client + clif_displaymessage(fd, text); + } + + return -1; + } + + // get possible name of the city + map_name[MAP_NAME_LENGTH-1] = '\0'; + for (i = 0; map_name[i]; i++) + map_name[i] = TOLOWER(map_name[i]); + // try to identify the map name + if (strncmp(map_name, "prontera", 3) == 0) { + town = 0; + } else if (strncmp(map_name, "morocc", 4) == 0 || + strncmp(map_name, "morroc", 4) == 0) { + town = 1; + } else if (strncmp(map_name, "geffen", 3) == 0) { + town = 2; + } else if (strncmp(map_name, "payon", 3) == 0) { + town = 3; + } else if (strncmp(map_name, "alberta", 3) == 0) { + town = 4; + } else if (strncmp(map_name, "izlude", 3) == 0) { + town = 5; + } else if (strncmp(map_name, "aldebaran", 3) == 0) { + town = 6; + } else if (strncmp(map_name, "lutie", 3) == 0 || + strcmp(map_name, "christmas") == 0 || + strncmp(map_name, "xmas", 3) == 0 || + strncmp(map_name, "x-mas", 3) == 0) { + town = 7; + } else if (strncmp(map_name, "comodo", 3) == 0) { + town = 8; + } else if (strncmp(map_name, "juno", 3) == 0 || + strncmp(map_name, "yuno", 3) == 0) { + town = 9; + } else if (strncmp(map_name, "amatsu", 3) == 0) { + town = 10; + } else if (strncmp(map_name, "kunlun", 3) == 0 || + strncmp(map_name, "gonryun", 3) == 0) { + town = 11; + } else if (strncmp(map_name, "umbala", 3) == 0) { + town = 12; + } else if (strncmp(map_name, "niflheim", 3) == 0) { + town = 13; + } else if (strncmp(map_name, "louyang", 3) == 0) { + town = 14; + } else if (strncmp(map_name, "new_1-1", 3) == 0 || + strncmp(map_name, "startpoint", 3) == 0 || + strncmp(map_name, "beginning", 3) == 0) { + town = 15; + } else if (strncmp(map_name, "sec_pri", 3) == 0 || + strncmp(map_name, "prison", 3) == 0 || + strncmp(map_name, "jail", 3) == 0) { + town = 16; + } else if (strncmp(map_name, "jawaii", 3) == 0) { + town = 17; + } else if (strncmp(map_name, "ayothaya", 3) == 0) { + town = 18; + } else if (strncmp(map_name, "einbroch", 5) == 0) { + town = 19; + } else if (strncmp(map_name, "lighthalzen", 3) == 0) { + town = 20; + } else if (strncmp(map_name, "einbech", 5) == 0) { + town = 21; + } else if (strncmp(map_name, "hugel", 3) == 0) { + town = 22; + } else if (strncmp(map_name, "rachel", 3) == 0) { + town = 23; + } else if (strncmp(map_name, "veins", 3) == 0) { + town = 24; + } else if (strncmp(map_name, "moscovia", 3) == 0) { + town = 25; + } else if (strncmp(map_name, "mid_camp", 3) == 0) { + town = 26; + } else if (strncmp(map_name, "manuk", 3) == 0) { + town = 27; + } else if (strncmp(map_name, "splendide", 3) == 0) { + town = 28; + } else if (strncmp(map_name, "brasilis", 3) == 0) { + town = 29; + } else if (strncmp(map_name, "dicastes01", 3) == 0) { + town = 30; + } else if (strcmp(map_name, "mora") == 0) { + town = 31; + } else if (strncmp(map_name, "dewata", 3) == 0) { + town = 32; + } else if (strncmp(map_name, "malangdo", 5) == 0) { + town = 33; + } else if (strncmp(map_name, "malaya", 5) == 0) { + town = 34; + } else if (strncmp(map_name, "eclage", 3) == 0) { + town = 35; + } + + if (town >= 0 && town < ARRAYLENGTH(data)) { + m = map_mapname2mapid(data[town].map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { + clif_displaymessage(fd, msg_txt(0)); // Warped. + } else { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } + } else { // if you arrive here, you have an error in town variable when reading of names + clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. + return -1; + } + + return 0; } /*========================================== @@ -2069,96 +2073,96 @@ ACMD_FUNC(go) *------------------------------------------*/ ACMD_FUNC(monster) { - char name[NAME_LENGTH]; - char monster[NAME_LENGTH]; - char eventname[EVENT_NAME_LENGTH] = ""; - int mob_id; - int number = 0; - int count; - int i, k, range; - short mx, my; - unsigned int size; - nullpo_retr(-1, sd); - - memset(name, '\0', sizeof(name)); - memset(monster, '\0', sizeof(monster)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. - return -1; - } - if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || - sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { - //All data can be left as it is. - } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { - //Here, it is possible name was not given and we are using monster for it. - if (count < 3) //Blank mob's name. - name[0] = '\0'; - } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { - //All data can be left as it is. - } else if (sscanf(message, "%23s", monster) > 0) { - //As before, name may be already filled. - name[0] = '\0'; - } else { - clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. - return -1; - } - - if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster)); - - if (mob_id == 0) { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - if (mob_id == MOBID_EMPERIUM) { - clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. - return -1; - } - - if (number <= 0) - number = 1; - - if( !name[0] ) - strcpy(name, "--ja--"); - - // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive - if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) - number = battle_config.atc_spawn_quantity_limit; - - if (strcmp(command+1, "monstersmall") == 0) - size = SZ_MEDIUM; // This is just gorgeous [mkbu95] - else if (strcmp(command+1, "monsterbig") == 0) - size = SZ_BIG; - else - size = SZ_SMALL; - - if (battle_config.etc_log) - ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); - - count = 0; - range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) - for (i = 0; i < number; i++) { - map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); - k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); - count += (k != 0) ? 1 : 0; - } - - if (count != 0) - if (number == count) - clif_displaymessage(fd, msg_txt(39)); // All monster summoned! - else { - sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! - clif_displaymessage(fd, atcmd_output); - } - else { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - return 0; + char name[NAME_LENGTH]; + char monster[NAME_LENGTH]; + char eventname[EVENT_NAME_LENGTH] = ""; + int mob_id; + int number = 0; + int count; + int i, k, range; + short mx, my; + unsigned int size; + nullpo_retr(-1, sd); + + memset(name, '\0', sizeof(name)); + memset(monster, '\0', sizeof(monster)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. + return -1; + } + if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || + sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { + //All data can be left as it is. + } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { + //Here, it is possible name was not given and we are using monster for it. + if (count < 3) //Blank mob's name. + name[0] = '\0'; + } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { + //All data can be left as it is. + } else if (sscanf(message, "%23s", monster) > 0) { + //As before, name may be already filled. + name[0] = '\0'; + } else { + clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. + return -1; + } + + if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) + mob_id = mobdb_checkid(atoi(monster)); + + if (mob_id == 0) { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + if (mob_id == MOBID_EMPERIUM) { + clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. + return -1; + } + + if (number <= 0) + number = 1; + + if (!name[0]) + strcpy(name, "--ja--"); + + // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive + if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) + number = battle_config.atc_spawn_quantity_limit; + + if (strcmp(command+1, "monstersmall") == 0) + size = SZ_MEDIUM; // This is just gorgeous [mkbu95] + else if (strcmp(command+1, "monsterbig") == 0) + size = SZ_BIG; + else + size = SZ_SMALL; + + if (battle_config.etc_log) + ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); + + count = 0; + range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) + for (i = 0; i < number; i++) { + map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); + k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); + count += (k != 0) ? 1 : 0; + } + + if (count != 0) + if (number == count) + clif_displaymessage(fd, msg_txt(39)); // All monster summoned! + else { + sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! + clif_displaymessage(fd, atcmd_output); + } + else { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + return 0; } /*========================================== @@ -2166,44 +2170,44 @@ ACMD_FUNC(monster) *------------------------------------------*/ static int atkillmonster_sub(struct block_list *bl, va_list ap) { - struct mob_data *md; - int flag; + struct mob_data *md; + int flag; - nullpo_ret(md=(struct mob_data *)bl); - flag = va_arg(ap, int); + nullpo_ret(md=(struct mob_data *)bl); + flag = va_arg(ap, int); - if (md->guardian_data) - return 0; //Do not touch WoE mobs! + if (md->guardian_data) + return 0; //Do not touch WoE mobs! - if (flag) - status_zap(bl,md->status.hp, 0); - else - status_kill(bl); - return 1; + if (flag) + status_zap(bl,md->status.hp, 0); + else + status_kill(bl); + return 1; } ACMD_FUNC(killmonster) { - int map_id, drop_flag; - char map_name[MAP_NAME_LENGTH_EXT]; - nullpo_retr(-1, sd); + int map_id, drop_flag; + char map_name[MAP_NAME_LENGTH_EXT]; + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || sscanf(message, "%15s", map_name) < 1) - map_id = sd->bl.m; - else { - if ((map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } + if (!message || !*message || sscanf(message, "%15s", map_name) < 1) + map_id = sd->bl.m; + else { + if ((map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } - drop_flag = strcmp(command+1, "killmonster2"); + drop_flag = strcmp(command+1, "killmonster2"); - map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); + map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); - clif_displaymessage(fd, msg_txt(165)); // All monsters killed! + clif_displaymessage(fd, msg_txt(165)); // All monsters killed! - return 0; + return 0; } /*========================================== @@ -2211,77 +2215,77 @@ ACMD_FUNC(killmonster) *------------------------------------------*/ ACMD_FUNC(refine) { - int i,j, position = 0, refine = 0, current_position, final_refine; - int count; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { - clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). - sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear - clif_displaymessage(fd, atcmd_output); - return -1; - } - - refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); - - count = 0; - for (j = 0; j < EQI_MAX-1; j++) { - if ((i = sd->equip_index[j]) < 0) - continue; - if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) - continue; - if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) - continue; - if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) - continue; - - if(position && !(sd->status.inventory[i].equip & position)) - continue; - - final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); - if (sd->status.inventory[i].refine != final_refine) { - sd->status.inventory[i].refine = final_refine; - current_position = sd->status.inventory[i].equip; - pc_unequipitem(sd, i, 3); - clif_refine(fd, 0, i, sd->status.inventory[i].refine); - clif_delitem(sd, i, 1, 3); - clif_additem(sd, i, 1, 0); - pc_equipitem(sd, i, current_position); - clif_misceffect(&sd->bl, 3); - count++; - } - } - - if (count == 0) - clif_displaymessage(fd, msg_txt(166)); // No item has been refined. - else if (count == 1) - clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. - else { - sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + int i,j, position = 0, refine = 0, current_position, final_refine; + int count; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { + clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). + sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear + clif_displaymessage(fd, atcmd_output); + return -1; + } + + refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); + + count = 0; + for (j = 0; j < EQI_MAX-1; j++) { + if ((i = sd->equip_index[j]) < 0) + continue; + if (j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) + continue; + if (j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) + continue; + if (j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) + continue; + + if (position && !(sd->status.inventory[i].equip & position)) + continue; + + final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); + if (sd->status.inventory[i].refine != final_refine) { + sd->status.inventory[i].refine = final_refine; + current_position = sd->status.inventory[i].equip; + pc_unequipitem(sd, i, 3); + clif_refine(fd, 0, i, sd->status.inventory[i].refine); + clif_delitem(sd, i, 1, 3); + clif_additem(sd, i, 1, 0); + pc_equipitem(sd, i, current_position); + clif_misceffect(&sd->bl, 3); + count++; + } + } + + if (count == 0) + clif_displaymessage(fd, msg_txt(166)); // No item has been refined. + else if (count == 1) + clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. + else { + sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -2289,58 +2293,58 @@ ACMD_FUNC(refine) *------------------------------------------*/ ACMD_FUNC(produce) { - char item_name[100]; - int item_id, attribute = 0, star = 0; - int flag = 0; - struct item_data *item_data; - struct item tmp_item; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && - sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 - )) { - clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). - return -1; - } - - if ( (item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL ) { - clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. - return -1; - } - - item_id = item_data->nameid; - - if (itemdb_isequip2(item_data)) { - if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) - attribute = ATTRIBUTE_NORMAL; - if (star < MIN_STAR || star > MAX_STAR) - star = 0; - memset(&tmp_item, 0, sizeof tmp_item); - tmp_item.nameid = item_id; - tmp_item.amount = 1; - tmp_item.identify = 1; - tmp_item.card[0] = CARD0_FORGE; - tmp_item.card[1] = item_data->type==IT_WEAPON? - ((star*5) << 8) + attribute:0; - tmp_item.card[2] = GetWord(sd->status.char_id, 0); - tmp_item.card[3] = GetWord(sd->status.char_id, 1); - clif_produceeffect(sd, 0, item_id); - clif_misceffect(&sd->bl, 3); - - if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } else { - sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. - clif_displaymessage(fd, atcmd_output); - return -1; - } - - return 0; + char item_name[100]; + int item_id, attribute = 0, star = 0; + int flag = 0; + struct item_data *item_data; + struct item tmp_item; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && + sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 + )) { + clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). + return -1; + } + + if ((item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL) { + clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. + return -1; + } + + item_id = item_data->nameid; + + if (itemdb_isequip2(item_data)) { + if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) + attribute = ATTRIBUTE_NORMAL; + if (star < MIN_STAR || star > MAX_STAR) + star = 0; + memset(&tmp_item, 0, sizeof tmp_item); + tmp_item.nameid = item_id; + tmp_item.amount = 1; + tmp_item.identify = 1; + tmp_item.card[0] = CARD0_FORGE; + tmp_item.card[1] = item_data->type==IT_WEAPON? + ((star*5) << 8) + attribute:0; + tmp_item.card[2] = GetWord(sd->status.char_id, 0); + tmp_item.card[3] = GetWord(sd->status.char_id, 1); + clif_produceeffect(sd, 0, item_id); + clif_misceffect(&sd->bl, 3); + + if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } else { + sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. + clif_displaymessage(fd, atcmd_output); + return -1; + } + + return 0; } /*========================================== @@ -2348,35 +2352,32 @@ ACMD_FUNC(produce) *------------------------------------------*/ ACMD_FUNC(memo) { - int position = 0; - nullpo_retr(-1, sd); + int position = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if( !message || !*message || sscanf(message, "%d", &position) < 1 ) - { - int i; - clif_displaymessage(sd->fd, msg_txt(668)); - for( i = 0; i < MAX_MEMOPOINTS; i++ ) - { - if( sd->status.memo_point[i].map ) - sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); - else - sprintf(atcmd_output, msg_txt(171), i); // %d - void - clif_displaymessage(sd->fd, atcmd_output); - } - return 0; - } + if (!message || !*message || sscanf(message, "%d", &position) < 1) { + int i; + clif_displaymessage(sd->fd, msg_txt(668)); + for (i = 0; i < MAX_MEMOPOINTS; i++) { + if (sd->status.memo_point[i].map) + sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); + else + sprintf(atcmd_output, msg_txt(171), i); // %d - void + clif_displaymessage(sd->fd, atcmd_output); + } + return 0; + } - if( position < 0 || position >= MAX_MEMOPOINTS ) - { - sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (position < 0 || position >= MAX_MEMOPOINTS) { + sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - pc_memo(sd, position); - return 0; + pc_memo(sd, position); + return 0; } /*========================================== @@ -2384,24 +2385,24 @@ ACMD_FUNC(memo) *------------------------------------------*/ ACMD_FUNC(gat) { - int y; - nullpo_retr(-1, sd); + int y; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - for (y = 2; y >= -2; y--) { - sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", - map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, - map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); + for (y = 2; y >= -2; y--) { + sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", + map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, + map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); - clif_displaymessage(fd, atcmd_output); - } + clif_displaymessage(fd, atcmd_output); + } - return 0; + return 0; } /*========================================== @@ -2409,19 +2410,19 @@ ACMD_FUNC(gat) *------------------------------------------*/ ACMD_FUNC(displaystatus) { - int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; - nullpo_retr(-1, sd); + int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { - clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). - return -1; - } - if (i < 2) flag = 1; - if (i < 3) tick = 0; + if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { + clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). + return -1; + } + if (i < 2) flag = 1; + if (i < 3) tick = 0; - clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); + clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); - return 0; + return 0; } /*========================================== @@ -2429,47 +2430,39 @@ ACMD_FUNC(displaystatus) *------------------------------------------*/ ACMD_FUNC(statuspoint) { - int point; - unsigned int new_status_point; - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). - return -1; - } - - if(point < 0) - { - if(sd->status.status_point < (unsigned int)(-point)) - { - new_status_point = 0; - } - else - { - new_status_point = sd->status.status_point + point; - } - } - else if(UINT_MAX - sd->status.status_point < (unsigned int)point) - { - new_status_point = UINT_MAX; - } - else - { - new_status_point = sd->status.status_point + point; - } - - if (new_status_point != sd->status.status_point) { - sd->status.status_point = new_status_point; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_status_point; + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). + return -1; + } + + if (point < 0) { + if (sd->status.status_point < (unsigned int)(-point)) { + new_status_point = 0; + } else { + new_status_point = sd->status.status_point + point; + } + } else if (UINT_MAX - sd->status.status_point < (unsigned int)point) { + new_status_point = UINT_MAX; + } else { + new_status_point = sd->status.status_point + point; + } + + if (new_status_point != sd->status.status_point) { + sd->status.status_point = new_status_point; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2477,48 +2470,40 @@ ACMD_FUNC(statuspoint) *------------------------------------------*/ ACMD_FUNC(skillpoint) { - int point; - unsigned int new_skill_point; - nullpo_retr(-1, sd); - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). - return -1; - } - - if(point < 0) - { - if(sd->status.skill_point < (unsigned int)(-point)) - { - new_skill_point = 0; - } - else - { - new_skill_point = sd->status.skill_point + point; - } - } - else if(UINT_MAX - sd->status.skill_point < (unsigned int)point) - { - new_skill_point = UINT_MAX; - } - else - { - new_skill_point = sd->status.skill_point + point; - } - - if (new_skill_point != sd->status.skill_point) { - sd->status.skill_point = new_skill_point; - clif_updatestatus(sd, SP_SKILLPOINT); - clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_skill_point; + nullpo_retr(-1, sd); + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). + return -1; + } + + if (point < 0) { + if (sd->status.skill_point < (unsigned int)(-point)) { + new_skill_point = 0; + } else { + new_skill_point = sd->status.skill_point + point; + } + } else if (UINT_MAX - sd->status.skill_point < (unsigned int)point) { + new_skill_point = UINT_MAX; + } else { + new_skill_point = sd->status.skill_point + point; + } + + if (new_skill_point != sd->status.skill_point) { + sd->status.skill_point = new_skill_point; + clif_updatestatus(sd, SP_SKILLPOINT); + clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2526,25 +2511,24 @@ ACMD_FUNC(skillpoint) *------------------------------------------*/ ACMD_FUNC(zeny) { - int zeny=0, ret=-1; - nullpo_retr(-1, sd); + int zeny=0, ret=-1; + nullpo_retr(-1, sd); - if (!message || !*message || (zeny = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). - return -1; - } + if (!message || !*message || (zeny = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). + return -1; + } - if(zeny > 0){ - if((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - } - else { - if( sd->status.zeny < -zeny ) zeny = -sd->status.zeny; - if((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - } - if(!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success - return 0; + if (zeny > 0) { + if ((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + } else { + if (sd->status.zeny < -zeny) zeny = -sd->status.zeny; + if ((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + } + if (!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success + return 0; } /*========================================== @@ -2552,61 +2536,61 @@ ACMD_FUNC(zeny) *------------------------------------------*/ ACMD_FUNC(param) { - int i, value = 0, new_value, max; - const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" }; - short* status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 ); - - if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if( battle_config.atcommand_max_stat_bypass ) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - - if(value < 0 && *status[i] <= -value) { - new_value = 1; - } else if(max - *status[i] < value) { - new_value = max; - } else { - new_value = *status[i] + value; - } - - if (new_value != *status[i]) { - *status[i] = new_value; - clif_updatestatus(sd, SP_STR + i); - clif_updatestatus(sd, SP_USTR + i); - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(42)); // Stat changed. - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int i, value = 0, new_value, max; + const char *param[] = { "str", "agi", "vit", "int", "dex", "luk" }; + short *status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + ARR_FIND(0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0); + + if (i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if (battle_config.atcommand_max_stat_bypass) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + + if (value < 0 && *status[i] <= -value) { + new_value = 1; + } else if (max - *status[i] < value) { + new_value = max; + } else { + new_value = *status[i] + value; + } + + if (new_value != *status[i]) { + *status[i] = new_value; + clif_updatestatus(sd, SP_STR + i); + clif_updatestatus(sd, SP_USTR + i); + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(42)); // Stat changed. + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2614,58 +2598,58 @@ ACMD_FUNC(param) *------------------------------------------*/ ACMD_FUNC(stat_all) { - int index, count, value, max, new_value; - short* status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - value = pc_maxparameter(sd); - max = pc_maxparameter(sd); - } else { - if( battle_config.atcommand_max_stat_bypass ) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - } - - count = 0; - for (index = 0; index < ARRAYLENGTH(status); index++) { - - if (value > 0 && *status[index] > max - value) - new_value = max; - else if (value < 0 && *status[index] <= -value) - new_value = 1; - else - new_value = *status[index] +value; - - if (new_value != (int)*status[index]) { - *status[index] = new_value; - clif_updatestatus(sd, SP_STR + index); - clif_updatestatus(sd, SP_USTR + index); - count++; - } - } - - if (count > 0) { // if at least 1 stat modified - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(84)); // All stats changed! - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. - else - clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. - return -1; - } - - return 0; + int index, count, value, max, new_value; + short *status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + value = pc_maxparameter(sd); + max = pc_maxparameter(sd); + } else { + if (battle_config.atcommand_max_stat_bypass) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + } + + count = 0; + for (index = 0; index < ARRAYLENGTH(status); index++) { + + if (value > 0 && *status[index] > max - value) + new_value = max; + else if (value < 0 && *status[index] <= -value) + new_value = 1; + else + new_value = *status[index] +value; + + if (new_value != (int)*status[index]) { + *status[index] = new_value; + clif_updatestatus(sd, SP_STR + index); + clif_updatestatus(sd, SP_USTR + index); + count++; + } + } + + if (count > 0) { // if at least 1 stat modified + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(84)); // All stats changed! + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. + else + clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. + return -1; + } + + return 0; } /*========================================== @@ -2673,40 +2657,40 @@ ACMD_FUNC(stat_all) *------------------------------------------*/ ACMD_FUNC(guildlevelup) { - int level = 0; - short added_level; - struct guild *guild_info; - nullpo_retr(-1, sd); + int level = 0; + short added_level; + struct guild *guild_info; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { - clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). - return -1; - } + if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { + clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). + return -1; + } - if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { - clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. - return -1; - } - //if (strcmp(sd->status.name, guild_info->master) != 0) { - // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. - // return -1; - //} + if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { + clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. + return -1; + } + //if (strcmp(sd->status.name, guild_info->master) != 0) { + // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. + // return -1; + //} - added_level = (short)level; - if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow - added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; - else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow - added_level = 1 - guild_info->guild_lv; + added_level = (short)level; + if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow + added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; + else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow + added_level = 1 - guild_info->guild_lv; - if (added_level != 0) { - intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); - clif_displaymessage(fd, msg_txt(179)); // Guild level changed. - } else { - clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. - return -1; - } + if (added_level != 0) { + intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); + clif_displaymessage(fd, msg_txt(179)); // Guild level changed. + } else { + clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2714,39 +2698,38 @@ ACMD_FUNC(guildlevelup) *------------------------------------------*/ ACMD_FUNC(makeegg) { - struct item_data *item_data; - int id, pet_id; - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). - return -1; - } - - if ((item_data = itemdb_searchname(message)) != NULL) // for egg name - id = item_data->nameid; - else - if ((id = mobdb_searchname(message)) != 0) // for monster name - ; - else - id = atoi(message); - - pet_id = search_petDB_index(id, PET_CLASS); - if (pet_id < 0) - pet_id = search_petDB_index(id, PET_EGG); - if (pet_id >= 0) { - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet( - sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); - } else { - clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. - return -1; - } - - return 0; + struct item_data *item_data; + int id, pet_id; + nullpo_retr(-1, sd); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). + return -1; + } + + if ((item_data = itemdb_searchname(message)) != NULL) // for egg name + id = item_data->nameid; + else if ((id = mobdb_searchname(message)) != 0) // for monster name + ; + else + id = atoi(message); + + pet_id = search_petDB_index(id, PET_CLASS); + if (pet_id < 0) + pet_id = search_petDB_index(id, PET_EGG); + if (pet_id >= 0) { + sd->catch_target_class = pet_db[pet_id].class_; + intif_create_pet( + sd->status.account_id, sd->status.char_id, + (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, + (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, + 100, 0, 1, pet_db[pet_id].jname); + } else { + clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. + return -1; + } + + return 0; } /*========================================== @@ -2754,15 +2737,15 @@ ACMD_FUNC(makeegg) *------------------------------------------*/ ACMD_FUNC(hatch) { - nullpo_retr(-1, sd); - if (sd->status.pet_id <= 0) - clif_sendegg(sd); - else { - clif_displaymessage(fd, msg_txt(181)); // You already have a pet. - return -1; - } + nullpo_retr(-1, sd); + if (sd->status.pet_id <= 0) + clif_sendegg(sd); + else { + clif_displaymessage(fd, msg_txt(181)); // You already have a pet. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2770,36 +2753,35 @@ ACMD_FUNC(hatch) *------------------------------------------*/ ACMD_FUNC(petfriendly) { - int friendly; - struct pet_data *pd; - nullpo_retr(-1, sd); + int friendly; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (friendly = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). - return -1; - } + if (!message || !*message || (friendly = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). + return -1; + } - pd = sd->pd; - if (!pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } + pd = sd->pd; + if (!pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } - if (friendly < 0 || friendly > 1000) - { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (friendly < 0 || friendly > 1000) { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - if (friendly == pd->pet.intimate) { - clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. - return -1; - } + if (friendly == pd->pet.intimate) { + clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. + return -1; + } - pet_set_intimate(pd, friendly); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. - return 0; + pet_set_intimate(pd, friendly); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. + return 0; } /*========================================== @@ -2807,34 +2789,34 @@ ACMD_FUNC(petfriendly) *------------------------------------------*/ ACMD_FUNC(pethungry) { - int hungry; - struct pet_data *pd; - nullpo_retr(-1, sd); + int hungry; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (hungry = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). - return -1; - } + if (!message || !*message || (hungry = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). + return -1; + } - pd = sd->pd; - if (!sd->status.pet_id || !pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - if (hungry < 0 || hungry > 100) { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } - if (hungry == pd->pet.hungry) { - clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. - return -1; - } + pd = sd->pd; + if (!sd->status.pet_id || !pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + if (hungry < 0 || hungry > 100) { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } + if (hungry == pd->pet.hungry) { + clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. + return -1; + } - pd->pet.hungry = hungry; - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. + pd->pet.hungry = hungry; + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. - return 0; + return 0; } /*========================================== @@ -2842,64 +2824,63 @@ ACMD_FUNC(pethungry) *------------------------------------------*/ ACMD_FUNC(petrename) { - struct pet_data *pd; - nullpo_retr(-1, sd); - if (!sd->status.pet_id || !sd->pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - pd = sd->pd; - if (!pd->pet.rename_flag) { - clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. - return -1; - } + struct pet_data *pd; + nullpo_retr(-1, sd); + if (!sd->status.pet_id || !sd->pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + pd = sd->pd; + if (!pd->pet.rename_flag) { + clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. + return -1; + } - pd->pet.rename_flag = 0; - intif_save_petdata(sd->status.account_id, &pd->pet); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. + pd->pet.rename_flag = 0; + intif_save_petdata(sd->status.account_id, &pd->pet); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. - return 0; + return 0; } /*========================================== * *------------------------------------------*/ -ACMD_FUNC(recall) { - struct map_session_data *pl_sd = NULL; +ACMD_FUNC(recall) +{ + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). + return -1; + } - if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) - { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) - { - clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. - return -1; - } + if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { + clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. - return -1; - } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. - return -1; - } - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); - sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! - clif_displaymessage(fd, atcmd_output); + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. + return -1; + } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. + return -1; + } + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); + sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -2908,19 +2889,19 @@ ACMD_FUNC(recall) { *------------------------------------------*/ ACMD_FUNC(char_block) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); + memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). + return -1; + } - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. + chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. - return 0; + return 0; } /*========================================== @@ -2940,84 +2921,84 @@ ACMD_FUNC(char_block) *------------------------------------------*/ ACMD_FUNC(char_ban) { - char * modif_p; - int year, month, day, hour, minute, second, value; - time_t timestamp; - struct tm *tmtime; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - - if (!message || !*message || sscanf(message, "%s %23[^\n]", atcmd_output, atcmd_player_name) < 2) { - clif_displaymessage(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish