/
backup/a/
color/
doc/mudprogs/
gods/
player/a/
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <mysql/mysql.h>
#include "mud.h"

/* you can look up on how to fully install MySQL support on mysql.com
   you'll need to add some linkage files to your makefile to get this to work
*/

#define DB_HOST "localhost" //If it's not then put in the host address
#define DB_USER "username" //The username of your database account..NOT SHELL
#define DB_PASS "password" //the password to said account
#define DB_DB   "swrsql" //The name of the database within the DBMS
#define DB_PORT        3306      //The port on which the db accepts connections
#define DB_SOCKET      0      //Shouldnt have to mess with
#define DB_CLIENT_FLAG 0      //once again...dont mess with it

/* DB_CONNECT_TIME_LIMIT is the amount of time in minutes 
   you want the connection to the DB to stay active
*/
#define DB_CONNECT_TIME_LIMIT 5

/* use whatever log code you want here */ 
#define SYS_LOG(x)  log_string(x)

/* these SHOULD be able to local */
/* i would add the following to your global header if your lazy
   or where applicable if your not. query_db should go in main as it
   will be used where ever you decided to load from the DB.
*/

/* opens a connection to the database.  This does not need to be
   called on system startup as the query function will check this
   for you.
*/
void connect_db()
{
    char output[MAX_STRING_LENGTH];
	if ((db = mysql_init(NULL)) == NULL)
	{
		SYS_LOG("connect_db: error on initialize");
		return;
	}
	if (!mysql_real_connect(db, DB_HOST, DB_USER, DB_PASS,
		DB_DB, DB_PORT, DB_SOCKET, DB_CLIENT_FLAG))
	{
		/*I have a seperate loging system for boot up
                  remove or change as needed
                */
		log_string("connect_db: error on connect");
		sprintf(output, "Error: %s", mysql_error(db));
		log_string(output);
 		return;
	}
        db_connect = TRUE;
        db_last_action = 0;
        	log_string("mysql connected");

	return;
}

/* closes the database connection */
void disconnect_db()
{
	mysql_close(db);
	db_connect = FALSE;
	db = NULL;
	log_string("mysql disconnected");
	return;
}

/* Function that physically send the query to the database and
   returns the results.  query parameter should look like any other
   sql query. ie SELECT name FROM t_player_name WHERE player_id > 0
   NOTE: you will still have to check to see if valid results are returned
   and then parse results by row. You can also use this for all sql statements
   not just selects.
*
MYSQL_RES *query_db(char *query)
{
        va_list         argp;
        int             i = 0;
        double          j = 0;
        char            *s = 0, *out = 0, *p = 0;
        char            safe [MAX_STRING_LENGTH];
        char            query [MAX_STRING_LENGTH];
                                
        *query = '\0';
        *safe = '\0';

        va_start (argp, fmt);
                        
        for ( p = fmt, out = query; *p != '\0'; p++ ) {
                if ( *p != '%' ) {
			*out++ = *p;
                        continue;
                }
        
                switch ( *++p ) {
                        case 'c':
                                i = va_arg (argp, int);
				out += sprintf (out, "%c", i);
                                break;
                        case 's':
                                s = va_arg (argp, char *);
				if ( !s ) {
					out += sprintf (out, " ");
					break;
				}
                                mysql_real_escape_string (db, safe, s, strlen(s));
                                out += sprintf (out, "%s", safe);
                                *safe = '\0';
                                break;
                        case 'd':
                                i = va_arg (argp, int);
                                out += sprintf (out, "%d", i);
                                break;
                        case 'f':
                                j = va_arg (argp, double);
                                out += sprintf (out, "%f", j);
                                break;
                        case '%':
                                out += sprintf (out, "%%");
                                break;
                }
        }
                 
	*out = '\0';

        va_end (argp);

        return mysql_store_result(mysql_real_query (db, query, strlen(query)));
}*/

MYSQL_RES *query_db(char *query)
{
	char buf[MAX_INPUT_LENGTH];
	buf[0] = '\0';

	if( !db_connect )
		connect_db();
	if( db == NULL )
	{
		SYS_LOG("NULL db in query_db.");
		return NULL;
	}
	if( query == NULL || query[0] == '\0')
	{
		SYS_LOG("Null query in query_db()");
		return NULL;
	}
 	if (mysql_real_query(db, query, strlen(query)))
	{
		SYS_LOG("query_db(): error on query");
		SYS_LOG("-----------Error in MySQL------------");
		SYS_LOG(query);
		SYS_LOG( mysql_error(db));
		return NULL;
	}
 	return mysql_store_result(db);
}
/*
 The call to this function should be made somewhere in your
   update calls..which every area you like that is called approx
   once per minute.  This kills the database connection if it has
   been idle for set period of time. This doesnt not have to be added
   but your sys admin might appreciate it.
*/
void check_db_disconnect()
{
	/* first check if we're even connected */
	if( !db_connect)
		return;
	/* No we see if we have been connected for too long,
	   if we have, lets disconnect and save resources
        */
	if( db_last_action >= DB_CONNECT_TIME_LIMIT)
	{
		disconnect_db();
		return;
	}
	/* at this point we must still be connected, so lets increment our time */
	db_last_action++;
	return;
}

/* function to make strings all nice and friendly with proper
   escape sequences and such.  Memory allocation should not be
   meddled with unless you know what you are doing.  Currently it assumes
   worst case..an escape for ever character plus the null terminator.
   I know this looks wierd..but it works. Use this when you are putting
   data into the database.
*/
char *sql_escape_string( char *source) 
{
	char *buf = '\0';
	char *ret = '\0';
	int len = 0;

	len = strlen( source );
	buf = malloc( (2 *len) + 1);
	mysql_real_escape_string( db, buf, source, len);
	ret = str_dup( buf );
	free( buf );
	return ret;
}


/* use this to see if any data was returned */
bool sql_data_returned( MYSQL_RES *result ) 
{
	if( mysql_num_rows( result ) )
		return TRUE;
	else
		return FALSE;
}

/* NOTE, these macros have not been tested, i simply added them in
   in the hope that they should work and allow you to understand how
   to use the results of a query
*/
/* start the loop */
#define PARSE_ROW( row, res) while( (row = mysql_fetch_row(res)) ) {
/* for getting string data back */
#define GET_ROW_S_DATA( item, field, row, num) (item)->field = str_dup( row[num] )
/* for getting numerical data back */
#define GET_ROW_N_DATA( item, field, row, num) (item)->field = atoi( row[num] )

/******************* EXAMPLE ON HOW TO USE *******************************
 MYSQL_ROW row;
 MYSQL_RES *result = NULL;
 SOME_DATA *thing = NULL;
 if( (result = query_db( some query text )) == FALSE ) {
   send some message some where
   exit out..or do whatever you want to do
 }
 -----with macros...assuming they work..you should be able to figure out what
 is going on from the macro definition
 PARSE_ROW( row, result)
    create memory for new item if needed...link to lists if needed
    GET_ROW_S_DATA( thing, name, row, 0);
    GET_ROW_N_DATA( thing, id_num, row, 1);
 }
 **********NOTE************
 the numbers for the row are dependant on how you have the columns
 set up in your database, if id_num came before name for example then switch the
 numbers.  Personally i would make a seperate header file to contain preprocessor
 defines for all the database row numbers...looking them up constantly is a pain
 in the ass
***************************************************************************/