/*************************************************************************** * STAR WARS REALITY 1.0 * *--------------------------------------------------------------------------* * Star Wars Reality Code Additions and changes from the Smaug Code * * copyright (c) 1997 by Sean Cooper * * -------------------------------------------------------------------------* * Starwars and Starwars Names copyright(c) Lucas Film Ltd. * *--------------------------------------------------------------------------* * SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Account Management * ****************************************************************************/ #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <time.h> #include <string.h> #include <fcntl.h> #include <signal.h> #include <stdarg.h> #include <sys/wait.h> #include <zlib.h> #include "mud.h" #include "sha256.h" /* TCP Defines */ #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <arpa/telnet.h> #include <netdb.h> const char account_echo_off_str[] = { ( char ) IAC, ( char ) WILL, TELOPT_ECHO, '\0' }; const char account_echo_on_str[] = { ( char ) IAC, ( char ) WONT, TELOPT_ECHO, '\0' }; /* Local Defines */ bool check_parse_name args( ( char *name ) ); bool check_playing args( ( DESCRIPTOR_DATA * d, char *name, bool kick ) ); bool check_reconnect args( ( DESCRIPTOR_DATA * d, char *name, bool fConn ) ); void show_title( DESCRIPTOR_DATA * d ); /******************************************************************************* ***************************** Dependant Functions ****************************** *******************************************************************************/ char *smash_color( char *str ) { static char ret[MAX_STRING_LENGTH]; char *retptr; retptr = ret; for( ; *str != '\0'; str++ ) { if( *str == '&' ) str++; else { *retptr = *str; retptr++; } } *retptr = '\0'; return ret; } /******************************************************************************* ******************************* Account Function ******************************* *******************************************************************************/ bool has_account( CHAR_DATA * ch ) { if( IS_NPC( ch ) ) return FALSE; if( ch->desc && ch->desc->account ) return TRUE; return FALSE; } bool account_exist( char *name ) { char strsave[MAX_INPUT_LENGTH]; FILE *fp; sprintf( strsave, "%s%c/%s", ACCOUNT_DIR, tolower( name[0] ), capitalize( name ) ); if( ( fp = fopen( strsave, "r" ) ) != NULL ) { fclose( fp ); return TRUE; } else return FALSE; } bool acc_char_playing( char *name ) { CHAR_DATA *ch; if( !name ) return FALSE; for( ch = first_char; ch; ch = ch->next ) if( !str_cmp( ch->name, name ) && !IS_NPC( ch ) ) return TRUE; return FALSE; } ACC_CHAR_DATA *get_char_account( ACCOUNT_DATA * account, char *name ) { ACC_CHAR_DATA *ch; for( ch = account->first_acc_char; ch; ch = ch->next ) if( !str_cmp( ch->name, name ) ) return ch; return NULL; } void dispose_acc_char( ACCOUNT_DATA * account, ACC_CHAR_DATA * ch ) { if( !ch ) return; if( ch->name ) STRFREE( ch->name ); if( ch->clan ) STRFREE( ch->clan ); if( ch->password ) STRFREE( ch->password ); if( ch->quit_location ) STRFREE( ch->quit_location ); UNLINK( ch, account->first_acc_char, account->last_acc_char, next, prev ); DISPOSE( ch ); } void dispose_account( ACCOUNT_DATA * account ) { ACC_CHAR_DATA *ch, *next_ch; if( !account ) return; if( account->name ) STRFREE( account->name ); for( ch = account->first_acc_char; ch; ch = next_ch ) { next_ch = ch->next; dispose_acc_char( account, ch ); } UNLINK( account, first_account, last_account, next, prev ); DISPOSE( account ); } bool check_multi_account( DESCRIPTOR_DATA * d ) { return FALSE; } /******************************************************************************* ******************************* Account Creation ******************************* *******************************************************************************/ ACCOUNT_DATA *create_account( char *name ) { ACCOUNT_DATA *account; if( !name ) return NULL; CREATE( account, ACCOUNT_DATA, 1 ); LINK( account, first_account, last_account, next, prev ); account->name = STRALLOC( name ); account->maxalts = 1; return account; } void save_account( ACCOUNT_DATA * account ) { FILE *fp; ACC_CHAR_DATA *ch; char filename[256]; if( !account ) return; sprintf( filename, "%s%c/%s", ACCOUNT_DIR, tolower( account->name[0] ), capitalize( account->name ) ); if( ( fp = fopen( filename, "w" ) ) != NULL ) { fprintf( fp, "Name %s~\n\r", account->name ); fprintf( fp, "Email %s~\n\r", account->email ); fprintf( fp, "Password %s~\n\r", account->password ); for( ch = account->first_acc_char; ch; ch = ch->next ) fprintf( fp, "Char %s~\n\r", ch->name ); fprintf( fp, "Host %s~\n\r", account->host ); fprintf( fp, "Last_played %s~\n\r", account->last_played ); fprintf( fp, "Timer %d\n\r", ( int ) account->timer ); fprintf( fp, "Multiplay %d\n\r", account->multiplay ); fprintf( fp, "Banned %d\n\r", account->banned ); fprintf( fp, "Points %d\n\r", account->points ); fprintf( fp, "Maxalts %d\n\r", account->maxalts ); fprintf( fp, "Verify %d\n\r", account->verify ); fprintf( fp, "Verified %d\n\r", account->verified ); fprintf( fp, "Attempts %d\n\r", account->attempts ); fprintf( fp, "PasswordFail %d\n\r", account->passwordfail ); fprintf( fp, "End\n\r" ); fclose( fp ); } } ACCOUNT_DATA *fread_account( char *name ) { FILE *fp; ACCOUNT_DATA *account; char filename[256], *word; bool fMatch = FALSE; if( !name ) return NULL; sprintf( filename, "%s%c/%s", ACCOUNT_DIR, tolower( name[0] ), capitalize( name ) ); if( ( fp = fopen( filename, "r" ) ) != NULL ) { CREATE( account, ACCOUNT_DATA, 1 ); LINK( account, first_account, last_account, next, prev ); account->alts = 0; account->immortal = FALSE; for( ;; ) { word = feof( fp ) ? ( char * ) "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER( word[0] ) ) { case 'A': KEY( "Attempts", account->attempts, fread_number( fp ) ); break; case 'B': KEY( "Banned", account->banned, fread_number( fp ) ); break; case 'C': if( !str_cmp( word, "Char" ) ) { char *string = fread_string( fp ); add_acc_char( account, string, FALSE, FALSE ); ++account->alts; if( string ) STRFREE( string ); fMatch = TRUE; break; } break; case 'E': KEY( "Email", account->email, fread_string_nohash( fp ) ); if( !str_cmp( word, "End" ) ) return account; break; case 'H': KEY( "Host", account->host, fread_string( fp ) ); break; case 'L': KEY( "Last_played", account->last_played, fread_string( fp ) ); break; case 'M': KEY( "Maxalts", account->maxalts, fread_number( fp ) ); KEY( "Multiplay", account->multiplay, fread_number( fp ) ); break; case 'N': KEY( "Name", account->name, fread_string( fp ) ); break; case 'P': KEY( "Password", account->password, fread_string_nohash( fp ) ); KEY( "PasswordFail", account->passwordfail, fread_number( fp ) ); KEY( "Points", account->points, fread_number( fp ) ); break; case 'T': KEY( "Timer", account->timer, fread_number( fp ) ); break; case 'V': KEY( "Verified", account->verified, fread_number( fp ) ); KEY( "Verify", account->verify, fread_number( fp ) ); break; } if( !fMatch ) bug( "Fread_account: No match '%s'", 0, word ); } fclose( fp ); } else return NULL; return account; } void fread_acc_char( ACC_CHAR_DATA * ch, FILE * fp ) { ROOM_INDEX_DATA *room; char *word; bool fMatch = FALSE; int room_num = 0; for( ;; ) { word = feof( fp ) ? ( char * ) "End" : fread_word( fp ); fMatch = FALSE; switch( UPPER( word[0] ) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'C': KEY( "Clan", ch->clan, fread_string( fp ) ); break; case 'E': if( !str_cmp( word, "End" ) ) { if( ( room = get_room_index( room_num ) ) != NULL ) ch->quit_location = STRALLOC( room->name ); return; } break; case 'P': KEY( "Password", ch->password, fread_string( fp ) ); break; case 'R': KEY( "Race", ch->race, fread_number( fp ) ); KEY( "Room", room_num, fread_number( fp ) ); break; case 'T': KEY( "Toplevel", ch->level, fread_number( fp ) ); break; } if( !fMatch ) fread_to_eol( fp ); } } /******************************************************************************* ******************************* Account Handlers ******************************* *******************************************************************************/ bool add_acc_char( ACCOUNT_DATA * account, char *name, bool pending, bool newbie ) { ACC_CHAR_DATA *ch; FILE *fp; char filename[256]; if( !account || !name ) return FALSE; if( newbie ) { CREATE( ch, ACC_CHAR_DATA, 1 ); LINK( ch, account->first_acc_char, account->last_acc_char, next, prev ); ch->name = STRALLOC( name ); ch->race = 0; ch->password = STRALLOC( "" ); ch->quit_location = STRALLOC( "Unknown" ); ch->level = 1; return TRUE; } sprintf( filename, "%s%c/%s", PLAYER_DIR, tolower( name[0] ), name ); if( ( fp = fopen( filename, "r" ) ) != NULL ) { CREATE( ch, ACC_CHAR_DATA, 1 ); LINK( ch, account->first_acc_char, account->last_acc_char, next, prev ); ch->name = STRALLOC( name ); fread_acc_char( ch, fp ); if( pending ) account->pending = ch; else { if( ch->level >= LEVEL_IMMORTAL ) { account->immortal = TRUE; account->maxalts = 5; account->points = 1000; } } fclose( fp ); return TRUE; } else return FALSE; } /******************************************************************************* ******************************* Account Colorize ******************************* *******************************************************************************/ void acolorize( char *in, char *out ) { char mesg[MAX_STRING_LENGTH]; char buf [MAX_STRING_LENGTH]; char *start; start = &in[0]; sprintf( mesg, "&W" ); while( *start) { if( ispunct( ( int ) * start ) && *start != '&' ) { sprintf( buf, "&B%c&W", *start ); strcat( mesg, buf ); } else { sprintf( buf, "%c", *start ); strcat( mesg, buf ); } ++start; } strcpy( out, mesg ); return; } void ad_printf( DESCRIPTOR_DATA * d, char *fmt, ... ) { char buf[MAX_STRING_LENGTH * 2]; char buf2[MAX_STRING_LENGTH * 2]; va_list args; va_start( args, fmt ); vsprintf( buf, fmt, args ); va_end( args ); acolorize( buf, buf2 ); send_to_desc_color( buf2, d ); return; } /******************************************************************************* ******************************** Account Display ******************************* *******************************************************************************/ void display_who( DESCRIPTOR_DATA * d ) { char buf[MAX_STRING_LENGTH]; int count = 0; DESCRIPTOR_DATA *d2; for( d2 = last_descriptor; d2; d2 = d2->prev ) { if( d2->connected != CON_PLAYING && d2->connected != CON_EDITING ) continue; if( IS_IMMORTAL( d2->character ) && IS_SET( d2->character->act, PLR_WIZINVIS ) && !d->account->immortal ) continue; sprintf( buf, "%s - %s\n\r", IS_IMMORTAL( d2->character ) ? "Immortal" : "Player", d2->character->pcdata->title ); ad_printf( d, buf ); count++; } if( !count ) ad_printf( d, "\n\rNobody playing.\n\r" ); } void display_account_menu( DESCRIPTOR_DATA * d ) { ad_printf( d, "\n\rEmail Address: &W" ); ad_printf( d, d->account->email ); ad_printf( d, "\n\r" ); ad_printf( d, "Account Name: %s\n\r", d->account->name ); ad_printf( d, "Account Status: %s", d->account->verified ? "Verified" : "Not Verified" ); ad_printf( d, "\n\r\n\r" ); ad_printf( d, "Play - plays designated character\n\r" ); ad_printf( d, "Create - creates a character to add to account\n\r" ); ad_printf( d, "Add - adds an existing character to account\n\r" ); ad_printf( d, "Remove - removes and deletes chracter from account\n\r" ); ad_printf( d, "Delete - this will delete your account and chracters\n\r" ); ad_printf( d, "Password - change your account password\n\r" ); ad_printf( d, "List - lists the characters currently in your account\n\r" ); ad_printf( d, "Menu - displays this menu\n\r" ); if( d->account->verified ) ad_printf( d, "Points - displays how many account points you currently have\n\r" ); if( d->account->verified ) ad_printf( d, "Who - see who is on the game\n\r" ); ad_printf( d, "Quit - terminates connection to your MUD\n\r" ); return; } void display_account_chars( DESCRIPTOR_DATA * d ) { ACC_CHAR_DATA *ch; char buf[MAX_STRING_LENGTH]; if( !d || !d->account ) return; ad_printf( d, "\n\rYou have %d characters on your account. Maximum limit is %d.\n\r", d->account->alts, d->account->maxalts ); ad_printf( d, "\n\rCharacter Race Clan Level Quit Room\n\r" ); for( ch = d->account->first_acc_char; ch; ch = ch->next ) { sprintf( buf, "%-15s %-15s %-20s %-5d %-20s\n\r", ch->name, npc_race[ch->race], ch->clan ? ch->clan : "None", ch->level, ch->quit_location ? smash_color( ch->quit_location ) : "None" ); ad_printf( d, buf ); } ad_printf( d, "\n\r" ); if( d->account->multiplay ) ad_printf( d, "This account may multiplay.\n\r" ); if( d->account->immortal ) ad_printf( d, "This account has immortal status.\n\r" ); return; } /******************************************************************************* ******************************** Account Interp ******************************** *******************************************************************************/ void account_interp( DESCRIPTOR_DATA * d, char *cmdline ) { ACC_CHAR_DATA *ch, *acc_char, *check; DESCRIPTOR_DATA *desc; char *arg; bool chk = FALSE; switch( d->connected ) { case CON_GET_ACCOUNT_NAME: if( cmdline[0] == '\0' ) { close_socket( d, FALSE ); return; } cmdline[0] = UPPER( cmdline[0] ); if( !check_parse_name( cmdline ) ) { ad_printf( d, "\n\rIllegal name, try again.\nEnter account name: &W" ); return; } if( strlen( cmdline ) < 4 ) { ad_printf( d, "\n\r\n\rAccount name is too short.\nEnter account name: &W\n\r" ); return; } if( strlen( cmdline ) > 15 ) { ad_printf( d, "\n\rAccount name cannot be longer than 15 characters.\nEnter account name: &W\n\r" ); return; } if( ( d->account = fread_account( cmdline ) ) != NULL ) { if( d->account->attempts >= 5 ) { sprintf( log_buf, "Locked account has been blocked: %s\n\r", d->account->name ); to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL ); ad_printf( d, "\n\rThis account has been locked for security purposes.\n\r" ); close_socket( d, FALSE ); } if( d->account->banned ) { sprintf( log_buf, "Banned account has been blocked: %s\n\r", d->account->name ); to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL ); ad_printf( d, "\n\rThis account has been banned.\n\r" ); close_socket( d, FALSE ); } if( !d->account->multiplay ) { for( desc = first_descriptor; desc; desc = desc->next ) { if( d != desc && desc->account && !str_cmp( d->host, desc->host ) && str_cmp( cmdline, desc->account->name ) && !str_cmp( desc->host, d->host ) ) { ad_printf( d, "\n\rSorry, multiplaying is not allowed... Have your other character quit first!\n\r" ); close_socket( d, FALSE ); } } } ad_printf( d, "\n\rEnter account password: " ); write_to_buffer( d, account_echo_off_str, 0 ); d->connected = CON_GET_ACCOUNT_OLD_PASS; } else { for( desc = first_descriptor; desc; desc = desc->next ) { if( d != desc && desc->account && !str_cmp( d->host, desc->host ) && str_cmp( cmdline, desc->account->name ) && !str_cmp( desc->host, d->host ) ) { ad_printf( d, "\n\rSorry, multiplaying is not allowed... Have your other character quit first!\n\r" ); close_socket( d, FALSE ); } } ad_printf( d, "\n\rAccount not found, we will create an account for the name provided.\nDo you accept this name? [Y/N]: " ); d->account = create_account( cmdline ); d->connected = CON_GET_ACCOUNT_NAME_CONFIRM; } break; case CON_GET_ACCOUNT_OLD_PASS: if( !strcmp( sha256_crypt( cmdline ), d->account->password ) ) { if( d->account->name ) ad_printf( d, "\n\r\n\rWelcome back %s!", d->account->name ); if( d->account->host ) { ad_printf( d, "\n\r\n\rLast logged in from: " ); ad_printf( d, d->account->host ); } if( d->account->last_played ) { ad_printf( d, "\n\rLast character played: " ); ad_printf( d, d->account->last_played ); ad_printf( d, "\n\r" ); } sprintf( log_buf, "Loading account: %s", d->account->name ); log_string( log_buf ); display_account_menu( d ); d->account->attempts = 0; ad_printf( d, "\n\rAccount> &W" ); if( d->account->host ) STRFREE( d->account->host ); d->account->host = STRALLOC( d->host ); write_to_buffer( d, account_echo_on_str, 0 ); d->connected = CON_ACCOUNT_PENDING; } else { ad_printf( d, "\n\rInvalid password, access denied.\n\r" ); d->account->attempts++; save_account( d->account ); close_socket( d, FALSE ); return; } break; case CON_GET_ACCOUNT_NAME_CONFIRM: switch( cmdline[0] ) { case 'y': case 'Y': ad_printf( d, "\n\rIs this your only account? &W" ); d->connected = CON_GET_ACCOUNT_FIRST; break; case 'n': case 'N': ad_printf( d, "\n\rEnter your desired account name: &W" ); dispose_account( d->account ); d->account = NULL; d->connected = CON_GET_ACCOUNT_NAME; break; default: ad_printf( d, "\n\rDo you accept this account name? [Y/N]: &W" ); break; } break; case CON_GET_ACCOUNT_FIRST: switch( cmdline[0] ) { case 'y': case 'Y': if( check_multi_account( d ) == TRUE ) { ad_printf( d, "\n\rAlternate account detected. You may only have one account. &W\n\r" ); close_socket( d, FALSE ); break; } sprintf( log_buf, "Creating new account: %s", d->account->name ); log_string( log_buf ); ad_printf( d, "\n\rEnter an email address: &W" ); write_to_buffer( d, account_echo_off_str, 0 ); d->connected = CON_ACCOUNT_GET_EMAIL; break; case 'n': case 'N': ad_printf( d, "\n\rSorry, you may only have one account. &W\n\r" ); close_socket( d, FALSE ); break; default: ad_printf( d, "\n\rIs this your only account, yes or no? [Y/N]: &W" ); break; } break; case CON_ACCOUNT_GET_EMAIL: if( strlen( cmdline ) < 8 ) { ad_printf( d, "\n\rYour email address is too short to be a valid email.\n\r\n\rEnter an email address: &W" ); return; } if( !strchr( cmdline, '@' ) ) { ad_printf( d, "\n\rEmail address does not contain @ symbol. Not valid.\n\r\n\rEnter an email address: &W" ); return; } if( !strchr( cmdline, '.' ) ) { ad_printf( d, "\n\rEmail address is not of proper format. Ex. example@email.com\n\r\n\rEnter an email address: &W" ); return; } if( strchr( cmdline, '~' ) ) { ad_printf( d, "\n\rEmail address cannot contain tilde symbol.\n\r\n\rEnter an email address: &W" ); return; } d->account->email = STRALLOC( cmdline ); d->account->last_played = STRALLOC( "" ); ad_printf( d, "\n\rEnter email address again: &W" ); write_to_buffer( d, account_echo_off_str, 0 ); d->connected = CON_ACCOUNT_CONFIRM_EMAIL; break; case CON_ACCOUNT_CONFIRM_EMAIL: if( strcmp( ( cmdline ), d->account->email ) ) { ad_printf( d, "\n\r\n\rEmail addresses do not match.\n\r\n\rEnter an email address: &W" ); d->connected = CON_ACCOUNT_GET_EMAIL; STRFREE( d->account->email ); return; } ad_printf( d, "\n\r\n\rEnter a password: " ); write_to_buffer( d, account_echo_off_str, 0 ); d->connected = CON_GET_ACCOUNT_NEW_PASS; break; case CON_GET_ACCOUNT_NEW_PASS: if( strlen( cmdline ) < 5 ) { ad_printf( d, "\n\rThe password must be at least 5 characters long.\n\r\n\rEnter a password: &W" ); return; } if( strchr( cmdline, '~' ) ) { ad_printf( d, "\n\rPassword may not contain tilde symbol.\n\r\n\rEnter a password: &W" ); return; } d->account->password = STRALLOC( sha256_crypt( cmdline ) ); ad_printf( d, "\n\rEnter password again: &W" ); d->connected = CON_ACCOUNT_CONFIRM_PASS; break; case CON_ACCOUNT_CONFIRM_PASS: if( strcmp( sha256_crypt( cmdline ), d->account->password ) ) { ad_printf( d, "\n\r\n\rPasswords do not match.\n\r\n\rEnter a password: &W" ); d->connected = CON_GET_ACCOUNT_NEW_PASS; STRFREE( d->account->password ); return; } write_to_buffer( d, account_echo_on_str, 0 ); sprintf( log_buf, "Loading account: %s", d->account->name ); log_string( log_buf ); ad_printf( d, "\n\r" ); save_account( d->account ); display_account_menu( d ); ad_printf( d, "\n\rAccount>&W " ); d->connected = CON_ACCOUNT_PENDING; return; case CON_ACCOUNT_ADD_CHAR_PASS: if( strcmp( sha256_crypt( cmdline ), d->account->pending->password ) ) { ad_printf( d, "\n\rInvalid password. Character not added.\n\r\n\rAccount> &W" ); sprintf( log_buf, "%s attempted to add %s to account. Wrong password.", d->account->name, d->account->pending->name ); log_string( log_buf ); dispose_acc_char( d->account, d->account->pending ); } else { add_acc_char( d->account, d->account->pending->name, FALSE, FALSE ); sprintf( log_buf, "%s has added '%s' to their account.", d->account->name, d->account->pending->name ); log_string( log_buf ); dispose_acc_char( d->account, d->account->pending ); ad_printf( d, "\n\rCharacter added.\n\r\n\rAccount> &W" ); d->account->alts++; save_account( d->account ); } d->account->pending = NULL; d->connected = CON_ACCOUNT_PENDING; write_to_buffer( d, account_echo_on_str, 0 ); break; case CON_ACCOUNT_PENDING: if( ( arg = strchr( cmdline, ' ' ) ) != NULL ) { *arg = '\0'; ++arg; } if( nifty_is_name_prefix( cmdline, "play" ) ) { if( !arg ) { ad_printf( d, "\n\rUsage: play <character name>\n\rAccount> &W" ); return; } if( ( ch = get_char_account( d->account, arg ) ) == NULL ) { ad_printf( d, "\n\rNo such player. See 'list' for details.\n\rAccount>&W " ); return; } if( !d->account->multiplay ) { for( acc_char = d->account->first_acc_char; acc_char; acc_char = acc_char->next ) { if( !str_cmp( acc_char->name, ch->name ) ) continue; if( acc_char_playing( acc_char->name ) ) { ad_printf( d, acc_char->name ); ad_printf( d, " is already playing. No multiplaying allowed on this account.\n\rAccount> &W" ); return; } } } if( check_playing( d, ch->name, FALSE ) == BERR ) { ad_printf( d, "\n\rName: " ); return; } if( d->account->timer > current_time && d->account->last_played && !d->account->multiplay && str_cmp( ch->name, d->account->last_played ) ) { char buf[MAX_STRING_LENGTH]; int ltime = ( int ) difftime( d->account->timer, current_time ); int minute = ltime / 60; int second = ltime % 60; sprintf( buf, "You must wait %d minute%s and %d second%s before playing that character.\n\r", minute, minute != 1 ? "s": "", second, second != 1 ? "s" : "" ); ad_printf( d, buf ); return; } if( load_char_obj( d, ch->name, TRUE, TRUE ) ) { char buf[MAX_STRING_LENGTH]; chk = check_reconnect( d, ch->name, FALSE ); if( chk == BERR ) return; if( check_playing( d, ch->name, TRUE ) ) return; chk = check_reconnect( d, ch->name, TRUE ); if( chk == BERR ) { close_socket( d, FALSE ); return; } if( chk == TRUE ) return; sprintf( buf, "%s", d->character->name ); d->character->desc = NULL; free_char( d->character ); load_char_obj( d, buf, FALSE, FALSE ); if( d->account->last_played ) STRFREE( d->account->last_played ); if( d->account->passwordfail > 1 ) d->account->passwordfail = 0; d->account->last_played = STRALLOC( ch->name ); save_account( d->account ); show_title( d ); } else { ad_printf( d, "\n\rCharacter not found.\n\rAccount> &W" ); } return; } else if( nifty_is_name_prefix( cmdline, "create" ) ) { if( d->account->alts >= d->account->maxalts ) { ad_printf( d, "\n\rYou may only have '%d' characters.\n\rAccount> &W", d->account->maxalts ); return; } sprintf( log_buf, "%s is creating a new character.", d->account->name ); log_string( log_buf ); ad_printf( d, "\n\rEnter name for character: &W" ); d->newstate = 1; d->connected = CON_GET_NAME; return; } else if( nifty_is_name_prefix( cmdline, "add" ) ) { if( d->account->alts >= d->account->maxalts ) { ad_printf( d, "\n\rYou have reached your limit on characters.\n\rAccount> &W" ); return; } if( !arg || arg[0] == '\0' ) { ad_printf( d, "\n\rAdd which character?\n\rAccount> &W" ); return; } arg[0] = toupper( arg[0] ); for( check = d->account->first_acc_char; check; check = check->next ) { if( !str_cmp( check->name, arg ) ) { ad_printf( d, "\n\rThat character has already been added to your account.\n\rAccount> &W" ); return; } } if( add_acc_char( d->account, arg, TRUE, FALSE ) ) { write_to_buffer( d, account_echo_off_str, 0 ); ad_printf( d, "\n\rEnter password for character: " ); d->connected = CON_ACCOUNT_ADD_CHAR_PASS; } else ad_printf( d, "\n\rCharacter not found.\n\rAccount> &W" ); return; } else if( nifty_is_name_prefix( cmdline, "remove" ) ) { ACC_CHAR_DATA *rch; char buf[MAX_STRING_LENGTH]; if( !d->account->verified ) { ad_printf( d, "\n\rAccount must be verified before you remove existing characters from it.\n\rAccount> &W" ); return; } if( !arg || arg[0] == '\0' ) { ad_printf( d, "\n\rRemove which character?\n\rAccount> &W" ); return; } arg[0] = toupper( arg[0] ); if( ( rch = get_char_account( d->account, arg ) ) == NULL ) { ad_printf( d, "\n\rThat character is not on your account.\n\rAccount> &W" ); return; } ad_printf( d, "\n\rPlayer removed from account and deleted.\n\rAccount> &W" ); sprintf( log_buf, "Deleting character: %s from %s's account.", rch->name, d->account->name ); log_string( log_buf ); sprintf( buf, "%s%c/%s", PLAYER_DIR, tolower( rch->name[0] ), rch->name ); remove( buf ); d->account->alts--; dispose_acc_char( d->account, rch ); save_account( d->account ); return; } else if( nifty_is_name_prefix( cmdline, "delete" ) ) { char account_buf[MAX_STRING_LENGTH]; char character_buf[MAX_STRING_LENGTH]; ACC_CHAR_DATA *player; if( d->account->passwordfail >= 3 ) { ad_printf( d, "\n\rAccount deletion has been locked due to too many failures.\n\rAccount> &W" ); return; } if( !arg ) { ad_printf( d, "\n\rYou must provide your password to delete your account!\n\rAccount> &W" ); return; } if( strcmp( sha256_crypt( arg ), d->account->password ) ) { ad_printf( d, "\n\rWrong password. Cannot delete account.\n\rAccount> &W" ); d->account->passwordfail++; save_account( d->account ); return; } else { sprintf( log_buf, "Deleting account: %s", d->account->name ); log_string( log_buf ); for( player = d->account->first_acc_char; player; player = player->next ) { sprintf( log_buf, "Deleting character: %s", player->name ); log_string( log_buf ); sprintf( character_buf, "%s%c/%s", PLAYER_DIR, tolower( player->name[0] ), player->name ); remove( character_buf ); } ad_printf( d, "\n\rYour account has been deleted... Goodbye!\n\r" ); sprintf( account_buf, "%s%c/%s", ACCOUNT_DIR, tolower( d->account->name[0] ), d->account->name ); remove( account_buf ); UNLINK( d->account, first_account, last_account, next, prev ); STRFREE( d->account->name ); DISPOSE( d->account ); close_socket( d, FALSE ); return; } } else if( nifty_is_name_prefix( cmdline, "password" ) ) { ad_printf( d, "\n\rCurrent account password:\n\r" ); d->connected = CON_ACCOUNT_GET_PASSWORD; return; } else if( nifty_is_name_prefix( cmdline, "list" ) ) { display_account_chars( d ); ad_printf( d, "\nAccount> &W" ); return; } else if( nifty_is_name_prefix( cmdline, "menu" ) ) { display_account_menu( d ); ad_printf( d, "\nAccount> &W" ); return; } else if( nifty_is_name_prefix( cmdline, "points" ) ) { char point_buf[MAX_STRING_LENGTH]; sprintf( point_buf, "\n\rYour account current has %d Account Points.\n\rAccount> &W", d->account->points ); ad_printf( d, point_buf ); return; } else if( nifty_is_name_prefix( cmdline, "who" ) ) { if( !d->account->verified ) { ad_printf( d, "\n\rAccount must be verified to use this function.\n\rAccount> &W" ); return; } display_who( d ); ad_printf( d, "\nAccount> &W" ); return; } else if( nifty_is_name_prefix( cmdline, "quit" ) ) { save_account( d->account ); sprintf( log_buf, "Close account: %s", d->account->name ); log_string( log_buf ); ad_printf( d, "\n\rGoodbye...\n\r" ); close_socket( d, FALSE ); return; } else { ad_printf( d, "\n\rCommand not found. See 'menu' for a list of valid commands.\n\rAccount> &W" ); return; } break; } } void account_password( DESCRIPTOR_DATA * d, char *cmdline ) { if( !d ) { ad_printf( d, "No descriptor present! Disconnecting...\n\r" ); close_socket( d, FALSE ); return; } switch( d->connected ) { case CON_ACCOUNT_GET_PASSWORD: if( strcmp( sha256_crypt( cmdline ), d->account->password ) ) { ad_printf( d, "\n\rInvalid password. Returning to menu.\n\r" ); display_account_menu( d ); d->connected = CON_ACCOUNT_PENDING; ad_printf( d, "\n\rAccount> &W" ); return; } ad_printf( d, "\n\rEnter new account password:\n\r" ); d->connected = CON_ACCOUNT_PASSWORD_NEW; break; case CON_ACCOUNT_PASSWORD_NEW: if( strlen( cmdline ) < 5 ) { ad_printf( d, "\n\rThe password must be at least 5 characters long.\n\rEnter new account password: " ); return; } if( strchr( cmdline, '~' ) ) { ad_printf( d, "\n\rPassword may not contain a tilde symbol.\n\rEnter new account password: " ); return; } d->account->temppass = STRALLOC( sha256_crypt( cmdline ) ); ad_printf( d, "\n\rConfirm new account password: " ); d->connected = CON_ACCOUNT_PASSWORD_CONFIRM; break; case CON_ACCOUNT_PASSWORD_CONFIRM: if( strcmp( sha256_crypt( cmdline ), d->account->temppass ) ) { ad_printf( d, "\n\rPasswords do not match. Failed to change password.\n\r" ); display_account_menu( d ); ad_printf( d, "Account> &W" ); d->connected = CON_ACCOUNT_PENDING; STRFREE( d->account->temppass ); return; } sprintf( log_buf, "%s changed their account password.", d->account->name ); log_string( log_buf ); d->account->password = STRALLOC( sha256_crypt( cmdline ) ); STRFREE( d->account->temppass ); ad_printf( d, "\n\rPassword changed successfully.\n\r" ); save_account( d->account ); display_account_menu( d ); ad_printf( d, "\n\rAccount> &W" ); d->connected = CON_ACCOUNT_PENDING; break; } } /******************************************************************************* ******************************* Account Commands ******************************* *******************************************************************************/ void do_account( CHAR_DATA * ch, char *argument ) { ACCOUNT_DATA *account; ACC_CHAR_DATA *accdata; int count = 0; if( IS_NPC( ch ) ) return; account = ch->desc->account; if( !account ) { send_to_char( "&RYou have no account!&D\n\r", ch ); return; } ch_printf( ch, "&WAccount Details&b:&D\n\r" ); ch_printf( ch, "&B---------------------------------------------------------------------&D\n\r" ); ch_printf( ch, "&WAccount Name&b: &z%-20s &WAccount Type&b: &z%s&D\n\r", account->name, account->immortal ? "Immortal" : "Player" ); ch_printf( ch, "&WCharacter &b: &z%-20s &WMultiplay &b: &z%s&D\n\r", ch->name, account->multiplay ? "Yes" : "No" ); ch_printf( ch, "&WPoints &b: &z%-5d &WEmail &b: &z%s&D\n\r", account->points, account->email ); ch_printf( ch, "&B---------------------------------------------------------------------&D\n\r" ); ch_printf( ch, "&WCharacter Race Clan Level Quit Room&D\n\r" ); for( accdata = account->first_acc_char; accdata; accdata = accdata->next ) { ch_printf( ch, "&W%-15s %-15s %-20s %-5d %-20s&D\n\r", accdata->name, npc_race[accdata->race], accdata->clan ? accdata->clan : "None", accdata->level, accdata->quit_location ? smash_color( accdata->quit_location ) : "None" ); count++; } if( !count ) { send_to_char( "&WNone.\n\r", ch ); return; } ch_printf( ch, "&B---------------------------------------------------------------------&D\n\r" ); ch_printf( ch, "\n\r&WYou have %d out of %d characters.&D\n\r", account->alts, account->maxalts ); return; } void do_verify( CHAR_DATA * ch, char *argument ) { ACCOUNT_DATA *account; char email[MAX_STRING_LENGTH]; char log[MAX_STRING_LENGTH]; int verification = 0; if( IS_NPC( ch ) ) return; account = ch->desc->account; if( !account ) { send_to_char( "&RYou have no account!&D\n\r", ch ); return; } if( NOT_AUTHED( ch ) ) { send_to_char( "&RYou cannot verify your account until after you are authorized!&D\n\r", ch ); return; } if( argument[0] == '\0' ) { if( account->verified ) { send_to_char( "&GYour account is already verified!\n\r", ch ); return; } send_to_char( "&RSyntax: verify send\n\r", ch ); send_to_char( "&R verify <verification number>&D\n\r", ch ); return; } if( !str_cmp( argument, "send" ) ) { if( account->verified ) { send_to_char( "&RYour account is already verified!\n\r", ch ); return; } if( account->verify > 0 ) { send_to_char( "&RIt seems we have already sent you an email verification.\n\r", ch ); send_to_char( "&RIf not, please contact an Immortal.\n\r", ch ); return; } if( !account->email ) { send_to_char( "&RYour account does not have an email address!\n\r", ch ); send_to_char( "&RUse 'email' command to set email address.\n\r", ch ); return; } verification = number_range( 11111, 99999 ); // Begin Email Function - Thanks to Xerves for the send_mail SMAUG snippet static char sendstring[1000]; FILE *fp = NULL; FILE *mfp = NULL; strcpy( sendstring, "" ); sprintf( email, "%s%s.account", EMAIL_DIR, capitalize( account->name ) ); fp = fopen( email, "w" ); fprintf( fp, "Hello %s!\n\n", account->name ); fprintf( fp, "While playing %s, you requested that we send\n", MUD_NAME ); fprintf( fp, "you a verifcation code for your account! The verification code is:\n" ); fprintf( fp, "\n%d\n\n", verification ); fclose( fp ); sprintf( sendstring, "%s -s \"Verification Email\" \"%s\" < %s", MAIL_ROOT_DIR, account->email, email ); sprintf( log, "Account: %s (%s): Verification email sent to %s\n\r", account->name, ch->name, account->email ); append_to_file( EMAIL_LOG, log ); if( ( mfp = popen( sendstring, "w" ) ) == NULL ) { send_to_char( "&RError. Mail function not found on this server! Inform an Immortal!\n\r", ch ); bug( "Error. Mail function not found for account verification!", 0 ); return; } pclose( mfp ); // End Email Function account->verify = verification; save_account( account ); ch_printf( ch, "&GA verification email has been sent to &W%s&D\n\r", account->email ); send_to_char( "&GIf you do not receive an email with an hour, please contact an Immortal\n\r", ch ); return; } if( account->verified ) { send_to_char( "&RYour account is already verified!\n\r", ch ); return; } if( !account->verify ) { send_to_char( "&RYour account doesn't have a verification number... Please 'send' for one.\n\r", ch ); return; } if( !isdigit( argument[0] ) ) { send_to_char( "&RVerification must be a number!\n\r", ch ); return; } if( atoi( argument ) != account->verify ) { send_to_char( "&RThat is not the verification number that we sent you!\n\r", ch ); return; } if( atoi( argument ) == account->verify ) { account->verified = 1; if( account->maxalts == 1 ) account->maxalts = 3; account->verify = 0; save_account( account ); send_to_char( "&GYou have verified your account!\n\r", ch ); sprintf( log_buf, "Account: %s (%s): Account has been verified.\n\r", account->name, ch->name ); append_to_file( EMAIL_LOG, log_buf ); log_string( log_buf ); return; } return; }