#include <ctype.h>
#include <sys/types.h>
#include <stdio.h>
#include "stdlib.h"
#include "syslog.h"
#include "define.h"
#include "struct.h"
account_data** account_list = NULL;
int max_account;
/*
* LOCAL FUNCTIONS
*/
account_data* existing_email ( const char* );
bool valid_acnt_name ( char* );
bool valid_email ( char* );
void send_email ( link_data*, bool );
void save_accounts ( void );
/*
* ACCOUNT_DATA
*/
Account_Data :: Account_Data( )
{
record_new( sizeof( account_data ), MEM_ACCOUNT );
name = empty_string;
email = empty_string;
pwd = empty_string;
confirm = empty_string;
new_email = empty_string;
notes = empty_string;
last_login = -1;
balance = 0;
players = 0;
banned = -1;
}
Account_Data :: ~Account_Data( )
{
record_delete( sizeof( account_data ), MEM_ACCOUNT );
free_string( name, MEM_ACCOUNT );
free_string( email, MEM_ACCOUNT );
free_string( new_email, MEM_ACCOUNT );
free_string( pwd, MEM_ACCOUNT );
free_string( confirm, MEM_ACCOUNT );
free_string( notes, MEM_ACCOUNT );
}
/*
* ACCOUNT FUNCTIONS
*/
void add_list( account_data* account )
{
int pos;
pos = pntr_search( account_list, max_account, account->name );
if( pos < 0 )
pos = -pos-1;
insert( account_list, max_account, account, pos );
}
void extract( account_data* account )
{
int pos;
pos = pntr_search( account_list, max_account, account->name );
if( pos >= 0 ) {
if( account_list[pos] != account )
bug( "Extract_Account: Wrong position!" );
else
remove( account_list, max_account, pos );
}
delete account;
}
/*
* FIND ACCOUNT ROUTINES
*/
account_data* find_account( char* name, bool all )
{
int pos;
pos = pntr_search( account_list, max_account, name );
if( pos < 0 )
pos = -pos-1;
if( !all )
for( ; pos < max_account
&& account_list[pos]->last_login == -1; pos++ );
return( pos != max_account
&& !strncasecmp( name, account_list[pos]->name, strlen( name ) )
? account_list[pos] : NULL );
}
account_data* account_arg( char*& argument )
{
int pos;
int i;
for( i = strlen( argument ); i > 0; ) {
pos = pntr_search( account_list, max_account, argument, i );
if( pos < 0 )
pos = -pos-1;
for( ; pos < max_account; pos++ )
if( account_list[pos]->last_login != -1 ) {
if( !strncasecmp( argument, account_list[pos]->name, i ) ) {
argument += i;
skip_spaces( argument );
return account_list[pos];
}
break;
}
for( ; --i > 0 && isgraph( argument[i] ); );
}
return NULL;
}
/*
* VALID ACCOUNT NAME
*/
bool valid_acnt_name( char* argument )
{
if( strlen( argument ) < 5 )
return FALSE;
return TRUE;
}
/*
* EMAIL ROUTINES
*/
account_data* existing_email( const char* argument )
{
int i;
for( i = 0; i < max_account; i++ )
if( !strcasecmp( account_list[i]->email, argument )
|| !strcasecmp( account_list[i]->new_email, argument ) )
return account_list[i];
return NULL;
}
bool valid_email( char* addr )
{
int i;
if( strlen( addr ) < 5 )
return FALSE;
for( i = 1; i < strlen( addr )-1; i++ )
if( addr[i] == (char) '@' )
break;
if( i == strlen( addr )-1 )
return FALSE;
for( i = 0; i < strlen( addr ); i++ )
if( !isalnum( addr[i] ) && addr[i] != (char) '@'
&& addr[i] != (char) '.' && addr[i] != (char) '_'
&& addr[i] != (char) '-' && addr[i] != (char) '!'
&& addr[i] != (char) '+' )
return FALSE;
return TRUE;
}
void send_email( link_data* link, bool change )
{
char tmp [ MAX_INPUT_LENGTH ];
char confirm [ 10 ];
account_data* account;
FILE* fp;
int i;
account = link->account;
for( i = 0; i < 8; i++ )
confirm[i] = 'a'+number_range( 0, 25 );
confirm[8] = '\0';
account->confirm = alloc_string( confirm, MEM_ACCOUNT );
account->last_login = current_time;
if( ( fp = open_file( "email.msg", "w" ) ) == NULL )
return;
if( change ) {
fprintf( fp, "A request was entered at forestsedge.com to change\n" );
fprintf( fp, "the email address of an account to this address. The\n" );
fprintf( fp, "confirmation code needed to complete this is given\n" );
fprintf( fp, "below.\n" );
fprintf( fp, "\n" );
fprintf( fp, " Account: %s\n", account->name );
fprintf( fp, " Prev Email: %s\n", account->email );
fprintf( fp, " New Email: %s\n", account->new_email );
fprintf( fp, " Confirmation Code: %s\n", confirm );
fprintf( fp, " Site of Request: %s\n", link->host );
}
else {
fprintf( fp, "A request was entered at forestsedge.com to open an\n" );
fprintf( fp, "account for this email address. If this is indeed\n" );
fprintf( fp, "the case your confirmation code is '%s'.\n", confirm );
fprintf( fp, "The request was from a user connected from %s.\n",
link->host );
}
fclose( fp );
sprintf( tmp, "./softmail %s", account->new_email );
system( tmp );
return;
}
/*
* NANNY ROUTINES
*/
void nanny_acnt_enter( link_data* link, char* argument )
{
account_data* account;
if( *argument == '\0' ) {
write_greeting( link );
link->connected = CON_INTRO;
return;
}
if( ( account = find_account( argument ) ) == NULL ) {
help_link( link, "Unfound_Acnt" );
send( link, "Account: " );
return;
}
if( is_banned( account, link ) )
return;
link->account = account;
if( account->email == empty_string ) {
help_link( link, "Confirm_Acnt" );
send( link, "Confirmation Code: " );
link->connected = CON_ACNT_CONFIRM;
return;
}
help_link( link, "Acnt_Check_Pwd" );
send( link, "Password: " );
switch( link->connected ) {
case CON_VE_ACCOUNT : link->connected = CON_VE_VALIDATE; break;
case CON_CE_ACCOUNT : link->connected = CON_CE_PASSWORD; break;
default : link->connected = CON_ACNT_CHECK_PWD; break;
}
return;
}
void nanny_acnt_check_pwd( link_data* link, char* argument )
{
if( strcmp( link->account->pwd, argument ) ) {
help_link( link, "Acnt_Bad_Pwd" );
link->connected = CON_PAGE;
return;
}
if( link->connected == CON_CE_PASSWORD ) {
help_link( link, "New_Email" );
send( link, "Current: %s\n\r\n\r", link->account->email );
send( link, "New Email: " );
link->connected = CON_CE_EMAIL;
}
else {
help_link( link, "Login_new_name" );
send( link, "Name: " );
link->connected = CON_GET_NEW_NAME;
}
return;
}
void nanny_acnt_confirm( link_data* link, char* argument )
{
account_data* account = link->account;
if( no_input( link, argument ) )
return;
if( strcmp( argument, link->account->confirm ) ) {
help_link( link, "Bad_Confirm" );
send( link, "Confirmation Code: " );
return;
}
if( link->connected == CON_VE_CONFIRM ) {
help_link( link, "Email_Changed" );
press_return( link );
link->connected = CON_PAGE;
free_string( account->email, MEM_ACCOUNT );
}
else {
send( link, "\n\r>> Account Validated. <<\n\r" );
help_link( link, "Login_new_name" );
send( link, "Name: " );
link->connected = CON_GET_NEW_NAME;
}
free_string( account->confirm, MEM_ACCOUNT );
account->email = account->new_email;
account->new_email = empty_string;
account->confirm = empty_string;
save_accounts( );
}
void nanny_acnt_name( link_data* link, char* argument )
{
if( no_input( link, argument ) )
return;
if( !valid_acnt_name( argument ) ) {
help_link( link, "Invalid_Acnt_Name" );
send( link, "Account: " );
return;
}
if( find_account( argument, TRUE ) != NULL ) {
help_link( link, "Existing_Acnt" );
send( link, "Account: " );
return;
}
link->account = new account_data;
link->account->name = alloc_string( argument, MEM_ACCOUNT );
add_list( link->account );
help_link( link, "Acnt_Pwd" );
send( link, "Password: " );
link->connected = CON_ACNT_PWD;
return;
}
void nanny_acnt_password( link_data* link, char* argument )
{
if( strlen( argument ) < 5 ) {
help_link( link, "Short_Acnt_Pwd" );
send( link, "Password: " );
return;
}
link->account->pwd = alloc_string( argument, MEM_ACCOUNT );
help_link( link, "Acnt_Email" );
send( link, "Email: " );
link->connected = CON_ACNT_EMAIL;
return;
}
void nanny_acnt_email( link_data* link, char* argument )
{
account_data* account = link->account;
if( no_input( link, argument ) )
return;
if( !valid_email( argument ) ) {
help_link( link, "Invalid_Email" );
send( link, "Email: " );
return;
}
if( existing_email( argument ) != NULL ) {
help_link( link, "Existing_Email" );
link->connected = CON_PAGE;
if( link->account->last_login == -1 ) {
extract( link->account );
link->account = NULL;
}
return;
}
if( is_banned( argument ) ) {
send( link,
"New accounts with email from that site are banned.\n\r" );
close_socket( link, TRUE );
return;
}
if( link->connected == CON_CE_EMAIL ) {
account->new_email = alloc_string( argument, MEM_ACCOUNT );
help_link( link, "ChangeEmail_Sent" );
press_return( link );
link->connected = CON_PAGE;
send_email( link, TRUE );
return;
}
link->connected = CON_ACNT_CHECK;
account->new_email = alloc_string( argument, MEM_ACCOUNT );
help_link( link, "Acnt_Check" );
send( link,
" Account: %s\n\r Password: %s\n\r Email: %s\n\r\n\r",
account->name, account->pwd, account->new_email );
send( link, "Is the correct? " );
return;
}
void nanny_acnt_check( link_data* link, char* argument )
{
if( toupper( *argument ) != 'Y' ) {
help_link( link, "Acnt_Cancel" );
extract( link->account );
link->account = NULL;
link->connected = CON_PAGE;
return;
}
link->connected = CON_PAGE;
send_email( link, FALSE );
save_accounts( );
help_link( link, "Acnt_Done" );
return;
}
void nanny_acnt_menu( link_data* link, char* argument )
{
switch( atoi( argument ) ) {
case 1:
if( is_banned( link->host ) ) {
send( link, "The site you are connected from is banned.\n\r" );
close_socket( link, TRUE );
return;
}
help_link( link, "Create_Account" );
link->connected = CON_ACNT_NAME;
break;
case 2:
help_link( link, "CE_AccountName" );
link->connected = CON_CE_ACCOUNT;
break;
case 3:
help_link( link, "CE_AccountName" );
link->connected = CON_VE_VALIDATE;
break;
case 4:
help_link( link, "Acnt_Request" );
link->connected = CON_ACNT_REQUEST;
send( link, "Email: " );
return;
default:
write_greeting( link );
link->connected = CON_INTRO;
return;
}
send( link, "Account: " );
return;
}
void nanny_acnt_request( link_data* link, char* argument )
{
char tmp [ THREE_LINES ];
account_data* account;
bool found = FALSE;
FILE* fp;
if( ( account = existing_email( argument ) ) == NULL ) {
help_link( link, "Acnt_No_Email" );
link->connected = CON_PAGE;
return;
}
if( ( fp = open_file( "email.msg", "w" ) ) == NULL )
return;
fprintf( fp, "A user connected from %s requested this\n", link->host );
fprintf( fp, "information be emailed to this address.\n\n" );
fprintf( fp, " Account Name: %s\n", account->name );
fprintf( fp, " Account Password: %s\n", account->pwd );
if( account->confirm != empty_string )
fprintf( fp, " Confirmation Code: %s\n", account->confirm );
fprintf( fp, "\n" );
for( int i = 0; i < max_pfile; i++ )
if( pfile_list[i]->account == account ) {
if( !found ) {
fprintf( fp, "%-20s%-15s%s\n", "Player", "Password", "Last Login" );
fprintf( fp, "%-20s%-15s%s\n", "------", "--------", "----------" );
found = TRUE;
}
fprintf( fp, "%-20s%-15s%s\n", pfile_list[i]->name,
pfile_list[i]->pwd, pfile_list[i]->last_host );
}
if( !found )
fprintf( fp, "No existing players on this account.\n" );
fclose( fp );
sprintf( tmp, "./softmail %s", account->email );
system( tmp );
help_link( link, "Acnt_Sent" );
link->connected = CON_PAGE;
return;
}
void nanny_ve_validate( link_data* link, char* argument )
{
account_data* account;
if( *argument == '\0' ) {
write_greeting( link );
link->connected = CON_INTRO;
return;
}
if( ( account = find_account( argument ) ) == NULL ) {
help_link( link, "Unfound_Acnt" );
send( link, "Account: " );
return;
}
if( account->new_email == empty_string ) {
help_link( link, "CE_norequest" );
link->connected = CON_PAGE;
return;
}
help_link( link, "CE_Code" );
send( link, "Confirmation Code: " );
link->account = account;
link->connected = CON_VE_CONFIRM;
return;
}
/*
* DISK ROUTINES
*/
void save_accounts( )
{
account_data* account;
FILE* fp;
if( ( fp = open_file( ACCOUNT_FILE, "w" ) ) == NULL )
return;
fprintf( fp, "%d\n\n", max_account );
for( int i = 0; i < max_account; i++ ) {
account = account_list[i];
fprintf( fp, "%s~\n", account->name );
fprintf( fp, "%s~\n", account->email );
fprintf( fp, "%s~\n", account->pwd );
fprintf( fp, "%s~\n", account->new_email );
fprintf( fp, "%s~\n", account->confirm );
fprintf( fp, "%s~\n", account->notes );
fprintf( fp, "%d %d %d\n\n", account->last_login,
account->balance, account->banned );
}
fclose( fp );
}
void load_accounts( )
{
account_data* account;
FILE* fp;
fprintf( stderr, "Loading Accounts...\n\r" );
if( ( fp = fopen( ACCOUNT_FILE, "r" ) ) == NULL ) {
bug( "Load_Accounts: Fopen Error" );
max_account = 0;
account_list = NULL;
return;
}
max_account = fread_number( fp );
account_list = new account_data* [ max_account ];
for( int i = 0; i < max_account; i++ ) {
account = new account_data;
account->name = fread_string( fp, MEM_ACCOUNT );
account->email = fread_string( fp, MEM_ACCOUNT );
account->pwd = fread_string( fp, MEM_ACCOUNT );
account->new_email = fread_string( fp, MEM_ACCOUNT );
account->confirm = fread_string( fp, MEM_ACCOUNT );
account->notes = fread_string( fp, MEM_ACCOUNT );
account->last_login = fread_number( fp );
account->balance = fread_number( fp );
account->banned = fread_number( fp );
account_list[i] = account;
}
fclose( fp );
}
/*
* LIST ACCOUNTS ROUTINE
*/
void display_pfile( char_data* ch, pfile_data* pfile, bool& first )
{
char tmp [ TWO_LINES ];
char host [ ONE_LINE ];
account_data* account;
account = pfile->account;
if( first ) {
first = FALSE;
sprintf( tmp, "%-14s%-30s%-18s%-10s%s\n\r",
"Character", "Site", "Last On", "Class", "Level" );
page_underlined( ch, tmp );
}
strncpy( host, pfile->last_host, 30 );
truncate( host, 28 );
sprintf( tmp, "%-14s%-30s%-18s%-10s%5d\n\r",
pfile->name, host,
ltime( pfile->last_on )+4,
clss_table[pfile->clss].name,
pfile->level );
page( ch, tmp );
}
void display_account( char_data* ch, account_data* account, bool& first )
{
char tmp [ TWO_LINES ];
if( first ) {
first = FALSE;
sprintf( tmp, "%-20s%-30s\n\r",
"Account", "Email" );
page_underlined( ch, tmp );
}
page( ch, "%-20s%-30s\n\r", account->name, account->email );
return;
}
void do_accounts( char_data* ch, char* argument )
{
account_data* account = NULL;
pfile_data* pfile;
wizard_data* imm = (wizard_data*) ch;
int flags;
bool first = TRUE;
int i;
if( !get_flags( ch, argument, &flags, "spP", "Accounts" ) )
return;;
if( is_set( &flags, 0 ) ) {
if( *argument == '\0' ) {
send( ch, "For what site do you wish to list the players?\n\r" );
return;
}
if( ( i = site_search( argument ) ) < 0 )
i = -i-1;
for( ; i < site_entries && !rstrncasecmp( site_list[i]->last_host,
argument, strlen( argument ) ); i++ )
if( imm->See_Account( site_list[i] ) )
display_pfile( ch, site_list[i], first );
if( first )
send( ch, "No players from that site.\n\r" );
return;
}
if( is_set( &flags, 2 ) ) {
if( *argument == '\0' ) {
send( ch,
"For which character to you wish to run a password match?\n\r" );
return;
}
if( ( pfile = find_pfile( argument, ch ) ) == NULL )
return;
for( i = 0; i < max_pfile; i++ )
if( !strcasecmp( pfile_list[i]->pwd, pfile->pwd )
&& imm->See_Account( pfile_list[i] ) )
display_pfile( ch, pfile_list[i], first );
return;
}
if( *argument == '\0' ) {
send( ch,
"For what player %sdo you wish to list an account summary?\n\r",
is_set( &flags, 2 ) ? "" : "or account " );
return;
}
if( is_set( &flags, 1 ) || ( account = find_account( argument ) ) == NULL ) {
if( ( pfile = find_pfile( argument ) ) == NULL ) {
send( ch, "No matching player %sfound.\n\r",
is_set( &flags, 1 ) ? "" : "or account " );
return;
}
if( !imm->See_Account( pfile ) ) {
send( ch, "You cannot view the account of %s.\n\r", pfile->name );
return;
}
if( ( account = pfile->account ) == NULL ) {
send( ch, "%s has no account.\n\r", pfile->name );
return;
}
}
page( ch, " Account: %s\n\r", account->name );
page( ch, " Email: %s\n\r", account->email );
if( is_god( ch ) )
page( ch, " Password: %s\n\r", account->pwd );
if( account->banned != -1 )
page( ch, " Banned: %s\n\r",
account->banned == 0 ? "forever" :
ltime( account->banned ) );
page( ch, "\n\r" );
for( i = 0; i < max_pfile; i++ )
if( pfile_list[i]->account == account
&& imm->See_Account( pfile_list[i] ) )
display_pfile( ch, pfile_list[i], first );
if( account->notes != empty_string ) {
page( ch, "\n\r" );
page_underlined( ch, "Pbug\n\r" );
page( ch, account->notes );
}
}
/*
* PURCHASE COMMAND
*/
bool lower_balance( char_data* ch, int amount )
{
account_data* account;
if( ( account = ch->pcdata->pfile->account ) == NULL ) {
send( ch, "You don't have an account.\n\r" );
return FALSE;
}
if( account->balance < amount ) {
send( ch, "Your account balance is $%.2f - requested purchase\
is $%.2f.\n\r", account->balance, amount );
return FALSE;
}
account->balance -= amount;
return TRUE;
}
void do_purchase( char_data* ch, char* argument )
{
if( is_mob( ch ) )
return;
player_data* pc = (player_data*) ch;
account_data* account;
if( ( account = ch->pcdata->pfile->account ) == NULL ) {
send( ch, "You lack an account.\n\r" );
return;
}
if( *argument == '\0' ) {
send( ch, "Balance: $%.2f\n\r", (float) account->balance/100 );
return;
}
int i;
int cost;
if( matches( argument, "gsp" ) ) {
if( !number_arg( argument, i ) ) {
send( pc, "How many gossip points do you wish to purchase at 500 per\
dollar?\n\r" );
return;
}
if( i <= 0 ) {
send( pc, "The resale value of gsps is nothing.\n\r" );
return;
}
if( pc->gossip_pts+i > 1000 ) {
send( pc, "You may have at maximum 1000 gossip points.\n\r" );
return;
}
cost = (4+i)/5;
if( lower_balance( ch, cost ) ) {
i = min( 5*cost, 1000-pc->gossip_pts );
pc->gossip_pts += i;
send( ch, "%s gossip points purchased for $%.2f.\n\r",
number_word( i ), (float) cost/100 );
}
return;
}
}