+void Bank_SetPin(int AcctID, int Pin)
+{
+ char *errmsg;
+ char *query = mkstr("UPDATE accounts SET acct_pin=%i WHERE acct_id=%i", Pin, AcctID);
+ int rv = Bank_int_QueryNone(gBank_Database, query, &errmsg);
+ if( rv != SQLITE_OK )
+ {
+ fprintf(stderr, "Bank_CreateAcct - SQLite Error: '%s'\n", errmsg);
+ fprintf(stderr, "Query = '%s'\n", query);
+ sqlite3_free(errmsg);
+ free(query);
+ return ;
+ }
+ free(query);
+}
+/*
+ * Create an iterator for user accounts
+ */
+tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMaxBalance, time_t LastSeen)
+{
+ char *query;
+ const char *balanceClause;
+ const char *lastSeenClause;
+ const char *orderClause;
+ const char *revSort;
+ sqlite3_stmt *ret;
+
+ // Balance condtion
+ if( Flags & BANK_ITFLAG_MINBALANCE )
+ balanceClause = " AND acct_balance>=";
+ else if( Flags & BANK_ITFLAG_MAXBALANCE )
+ balanceClause = " AND acct_balance<=";
+ else {
+ balanceClause = " AND 1!=";
+ MinMaxBalance = 0;
+ }
+
+ // Last seen condition
+ if( Flags & BANK_ITFLAG_SEENAFTER )
+ lastSeenClause = " AND acct_last_seen>=";
+ else if( Flags & BANK_ITFLAG_SEENBEFORE )
+ lastSeenClause = " AND acct_last_seen<=";
+ else {
+ lastSeenClause = " AND datetime(-1,'unixepoch')!=";
+ }
+
+ // Sorting clause
+ switch( Flags & BANK_ITFLAG_SORTMASK )
+ {
+ case BANK_ITFLAG_SORT_NONE:
+ orderClause = "";
+ revSort = "";
+ break;
+ case BANK_ITFLAG_SORT_NAME:
+ orderClause = "ORDER BY acct_name";
+ revSort = " DESC";
+ break;
+ case BANK_ITFLAG_SORT_BAL:
+ orderClause = "ORDER BY acct_balance";
+ revSort = " DESC";
+ break;
+ case BANK_ITFLAG_SORT_LASTSEEN:
+ orderClause = "ORDER BY acct_balance";
+ revSort = " DESC";
+ break;
+ default:
+ fprintf(stderr, "BUG: Unknown sort (%x) in SQLite CokeBank\n", Flags & BANK_ITFLAG_SORTMASK);
+ return NULL;
+ }
+ if( !(Flags & BANK_ITFLAG_REVSORT) )
+ revSort = "";
+
+ #define MAP_FLAG(name, flag) (FlagMask&(flag)?(FlagValues&(flag)?" AND "name"=1":" AND "name"=0"):"")
+ query = mkstr("SELECT acct_id FROM accounts WHERE 1=1"
+ "%s%s%s%s%s" // Flags
+ "%s%i" // Balance
+ "%sdatetime(%"PRIu64",'unixepoch')" // Last seen
+ "%s%s" // Sort and direction
+ ,
+ MAP_FLAG("acct_is_coke", USER_FLAG_COKE),
+ MAP_FLAG("acct_is_admin", USER_FLAG_ADMIN),
+ MAP_FLAG("acct_is_door", USER_FLAG_DOORGROUP),
+ MAP_FLAG("acct_is_internal", USER_FLAG_INTERNAL),
+ MAP_FLAG("acct_is_disabled", USER_FLAG_DISABLED),
+ balanceClause, MinMaxBalance,
+ lastSeenClause, (uint64_t)LastSeen,
+ orderClause, revSort
+ );
+ //printf("query = \"%s\"\n", query);
+ #undef MAP_FLAG
+
+ ret = Bank_int_MakeStatemnt(gBank_Database, query);
+ if( !ret ) return NULL;
+
+ free(query);
+
+ return (void*)ret;
+}
+
+/*
+ * Get the next account in an iterator
+ */
+int Bank_IteratorNext(tAcctIterator *It)
+{
+ int rv;
+ rv = sqlite3_step( (sqlite3_stmt*)It );
+
+ if( rv == SQLITE_DONE ) return -1;
+ if( rv != SQLITE_ROW ) {
+ fprintf(stderr, "Bank_IteratorNext - SQLite Error: %s\n", sqlite3_errmsg(gBank_Database));
+ return -1;
+ }
+
+ return sqlite3_column_int( (sqlite3_stmt*)It, 0 );
+}
+
+/*
+ * Free an interator
+ */
+void Bank_DelIterator(tAcctIterator *It)
+{
+ sqlite3_finalize( (sqlite3_stmt*)It );
+}
+
+/*
+ * Check user authentication token
+ */
+int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password)
+{
+ Salt = Password = Username; // Shut up GCC
+ Password = Salt;
+ // DEBUG HACKS!
+ #if 0
+ return Bank_GetAcctByName(Username);
+ #else
+ return -1;
+ #endif
+}
+
+/*
+ * Get an account number given a card ID
+ * NOTE: Actually ends up just being an alternate authentication token,
+ * as no checking is done on the ID's validity, save for SQL sanity.
+ */
+int Bank_GetAcctByCard(const char *CardID)
+{
+ char *query;
+ sqlite3_stmt *statement;
+ int ret;
+
+ if( !Bank_int_IsValidName(CardID) )
+ return -1;
+
+ query = mkstr("SELECT acct_id FROM cards WHERE card_name='%s' LIMIT 1", CardID);
+ statement = Bank_int_QuerySingle(gBank_Database, query);
+ free(query);
+ if( !statement ) return -1;
+
+ ret = sqlite3_column_int(statement, 0);
+
+ sqlite3_finalize(statement);
+
+ return ret;
+}
+
+/*
+ * Add a card to an account
+ */
+int Bank_AddAcctCard(int AcctID, const char *CardID)
+{
+ char *query;
+ int rv;
+ char *errmsg;
+
+ if( !Bank_int_IsValidName(CardID) )
+ return -1;
+
+ // TODO: Check the AcctID too
+
+ // Insert card
+ query = mkstr("INSERT INTO cards (acct_id,card_name) VALUES (%i,'%s')",
+ AcctID, CardID);
+ rv = Bank_int_QueryNone(gBank_Database, query, &errmsg);
+ if( rv == SQLITE_CONSTRAINT )
+ {
+ sqlite3_free(errmsg);
+ free(query);
+ return 2; // Card in use
+ }
+ if( rv != SQLITE_OK )
+ {
+ fprintf(stderr, "Bank_AddAcctCard - SQLite Error: '%s'\n", errmsg);
+ fprintf(stderr, "Query = '%s'\n", query);
+ sqlite3_free(errmsg);
+ free(query);
+ return -1;
+ }
+ free(query);
+
+ return 0;
+}
+
+/*
+ * Create a SQLite Statement
+ */