From df71d48cc0082a5333203384cfbce040cf54a155 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 2 Feb 2011 21:24:15 +0800 Subject: [PATCH] Fixes to bugs pointed by [BOB] - Error in SQL code (assumed time_t was 64-bits) - Lack of `dispense acct =` (still needs client support) - Bumped the coke read timeout down - Made balance alter happen after the dispense --- cokebank.db | 1 + cokebank.so | 1 + src/cokebank_sqlite/main.c | 5 +-- src/server/common.h | 1 + src/server/dispense.c | 74 +++++++++++++++++++++++++++----------- src/server/handler_coke.c | 4 ++- src/server/server.c | 69 +++++++++++++++++++++++++++++++++++ 7 files changed, 132 insertions(+), 23 deletions(-) create mode 120000 cokebank.db create mode 120000 cokebank.so diff --git a/cokebank.db b/cokebank.db new file mode 120000 index 0000000..0508c2f --- /dev/null +++ b/cokebank.db @@ -0,0 +1 @@ +cokebank_sqlite.db \ No newline at end of file diff --git a/cokebank.so b/cokebank.so new file mode 120000 index 0000000..4548509 --- /dev/null +++ b/cokebank.so @@ -0,0 +1 @@ +cokebank_sqlite.so \ No newline at end of file diff --git a/src/cokebank_sqlite/main.c b/src/cokebank_sqlite/main.c index c112260..0d5e139 100644 --- a/src/cokebank_sqlite/main.c +++ b/src/cokebank_sqlite/main.c @@ -7,6 +7,7 @@ * This file is licenced under the 3-clause BSD Licence. See the file * COPYING for full details. */ +#include #include #include #include @@ -386,7 +387,7 @@ tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMax query = mkstr("SELECT acct_id FROM accounts WHERE 1=1" "%s%s%s%s%s" // Flags "%s%i" // Balance - "%sdatetime(%lli,'unixepoch')" // Last seen + "%sdatetime(%"PRIu64",'unixepoch')" // Last seen "%s%s" // Sort and direction , MAP_FLAG("acct_is_coke", USER_FLAG_COKE), @@ -395,7 +396,7 @@ tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMax MAP_FLAG("acct_is_internal", USER_FLAG_INTERNAL), MAP_FLAG("acct_is_disabled", USER_FLAG_DISABLED), balanceClause, MinMaxBalance, - lastSeenClause, LastSeen, + lastSeenClause, (uint64_t)LastSeen, orderClause, revSort ); //printf("query = \"%s\"\n", query); diff --git a/src/server/common.h b/src/server/common.h index 8aaf4c0..06a9100 100644 --- a/src/server/common.h +++ b/src/server/common.h @@ -81,6 +81,7 @@ extern char *mkstr(const char *Format, ...); extern int DispenseItem(int ActualUser, int User, tItem *Item); extern int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven); extern int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven); +extern int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven); extern int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven); // --- Logging --- diff --git a/src/server/dispense.c b/src/server/dispense.c index 09fe567..52d978c 100644 --- a/src/server/dispense.c +++ b/src/server/dispense.c @@ -5,6 +5,7 @@ #include int _GetMinBalance(int Account); + int _CanTransfer(int Source, int Destination, int Ammount); int _Transfer(int Source, int Destination, int Ammount, const char *Reason); // === CODE === @@ -15,10 +16,17 @@ */ int DispenseItem(int ActualUser, int User, tItem *Item) { - int ret; + int ret, salesAcct; tHandler *handler; char *username, *actualUsername; - char *reason; + + salesAcct = Bank_GetAcctByName(COKEBANK_SALES_ACCT); + + // Check if the user can afford it + if( Item->Price && !_CanTransfer(User, salesAcct, Item->Price) ) + { + return 2; // 2: No balance + } handler = Item->Handler; @@ -27,16 +35,6 @@ int DispenseItem(int ActualUser, int User, tItem *Item) ret = handler->CanDispense( User, Item->ID ); if(ret) return 1; // 1: Unable to dispense } - - // Subtract the balance - if( Item->Price ) - { - reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name); - if( !reason ) reason = Item->Name; // TODO: Should I instead return an error? - ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_SALES_ACCT), Item->Price, reason); - free(reason); - if(ret) return 2; // 2: No balance - } // Get username for debugging username = Bank_GetAcctName(User); @@ -45,15 +43,22 @@ int DispenseItem(int ActualUser, int User, tItem *Item) if( handler->DoDispense ) { ret = handler->DoDispense( User, Item->ID ); if(ret) { - Log_Error("Dispense failed after deducting cost (%s dispensing %s - %ic)", + Log_Error("Dispense failed (%s dispensing '%s' - %ic)", username, Item->Name, Item->Price); - if( Item->Price ) - _Transfer( Bank_GetAcctByName(COKEBANK_SALES_ACCT), User, Item->Price, "rollback" ); free( username ); - return -1; // 1: Unkown Error again + return -1; // 1: Unknown Error again } } + // Take away money + if( Item->Price ) + { + char *reason; + reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name); + _Transfer( User, salesAcct, Item->Price, reason ); + free(reason); + } + actualUsername = Bank_GetAcctName(ActualUser); // And log that it happened @@ -123,6 +128,26 @@ int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven) return 0; } +int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven) +{ + int curBal = Bank_GetBalance(User); + char *byName, *dstName; + + _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Balance-curBal, ReasonGiven ); + + byName = Bank_GetAcctName(ActualUser); + dstName = Bank_GetAcctName(User); + + Log_Info("set balance of %s to %i by %s [balance %i] - %s", + dstName, Balance, byName, Bank_GetBalance(User), ReasonGiven + ); + + free(byName); + free(dstName); + + return 0; +} + /** * \brief Donate money to the club */ @@ -167,18 +192,27 @@ int _GetMinBalance(int Account) return 0; } -int _Transfer(int Source, int Destination, int Ammount, const char *Reason) +/** + * \brief Check if a transfer is possible + */ +int _CanTransfer(int Source, int Destination, int Ammount) { if( Ammount > 0 ) { if( Bank_GetBalance(Source) + Ammount < _GetMinBalance(Source) ) - return 1; + return 0; } else { if( Bank_GetBalance(Destination) - Ammount < _GetMinBalance(Destination) ) - return 1; + return 0; } - + return 1; +} + +int _Transfer(int Source, int Destination, int Ammount, const char *Reason) +{ + if( !_CanTransfer(Source, Destination, Ammount) ) + return 1; return Bank_Transfer(Source, Destination, Ammount, Reason); } diff --git a/src/server/handler_coke.c b/src/server/handler_coke.c index a6b3cb9..4043cfc 100644 --- a/src/server/handler_coke.c +++ b/src/server/handler_coke.c @@ -18,6 +18,8 @@ #include #include +#define READ_TIMEOUT 2 // 2 seconds for ReadChar + // === IMPORTS === // === PROTOTYPES === @@ -191,7 +193,7 @@ char ReadChar() int ret; struct timeval timeout; - timeout.tv_sec = 5; // 5 second timeout + timeout.tv_sec = READ_TIMEOUT; timeout.tv_usec = 0; FD_ZERO(&readfs); diff --git a/src/server/server.c b/src/server/server.c index 9c36f3d..ca4aceb 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -771,6 +771,75 @@ void Server_Cmd_ADD(tClient *Client, char *Args) } } +void Server_Cmd_SET(tClient *Client, char *Args) +{ + char *user, *ammount, *reason; + int uid, iAmmount; + + if( !Client->bIsAuthed ) { + sendf(Client->Socket, "401 Not Authenticated\n"); + return ; + } + + user = Args; + + ammount = strchr(Args, ' '); + if( !ammount ) { + sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 1 encountered\n"); + return ; + } + *ammount = '\0'; + ammount ++; + + reason = strchr(ammount, ' '); + if( !reason ) { + sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 2 encountered\n"); + return ; + } + *reason = '\0'; + reason ++; + + // Check user permissions + if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) ) { + sendf(Client->Socket, "403 Not an admin\n"); + return ; + } + + // Get recipient + uid = Bank_GetAcctByName(user); + if( uid == -1 ) { + sendf(Client->Socket, "404 Invalid user\n"); + return ; + } + + // You can't alter an internal account + if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) { + sendf(Client->Socket, "404 Invalid user\n"); + return ; + } + + // Parse ammount + iAmmount = atoi(ammount); + if( iAmmount == 0 && ammount[0] != '0' ) { + sendf(Client->Socket, "407 Invalid Argument\n"); + return ; + } + + // Do give + switch( DispenseSet(Client->UID, uid, iAmmount, reason) ) + { + case 0: + sendf(Client->Socket, "200 Add OK\n"); + return ; + case 2: + sendf(Client->Socket, "402 Poor Guy\n"); + return ; + default: + sendf(Client->Socket, "500 Unknown error\n"); + return ; + } +} + void Server_Cmd_ENUMUSERS(tClient *Client, char *Args) { int i, numRet = 0; -- 2.20.1