'''
account_handler.py
The login and creation of accounts, and handles all account procedures, loading
and deleting, of characters.
'''
import mud, mudsys, char, hooks, account, socket, event, telnetlib
# control sequences for squelching passwords
squelch = telnetlib.IAC + telnetlib.WILL + telnetlib.ECHO
unsquelch = telnetlib.IAC + telnetlib.WONT + telnetlib.ECHO
def check_acct_name(name):
'''Makes sure an account name is valid'''
return (len(name) > 3 and len(name) < 13 and
name[0].isalpha() and name.isalnum())
def acct_name_prompt(sock):
sock.send_raw("What is your account name? ")
def acct_new_password_prompt(sock):
sock.send_raw("What is your new password? " + squelch)
def acct_password_prompt(sock):
sock.send_raw("What is your password? " + squelch)
def acct_confirm_password_prompt(sock):
sock.send_raw("\r\nVerify your password? " + squelch)
def acct_wait_dns_prompt(sock):
sock.send_raw("Resolving your internet address, have patience... ")
def acct_finish_prompt(sock):
sock.send_raw("{c\r\n*** Press enter to finish account creation:{n ")
def acct_finish_handler(sock, arg):
# pop our input handler for finishing account generation
sock.pop_ih()
# log that the account created
mud.log_string("New account '" + sock.account.name + "' has created.")
# register and save the account to disk
mudsys.do_register(sock.account)
def acct_wait_dns_handler(sock, arg):
# do nothing
return
def acct_name_handler(sock, arg):
'''the first prompt a socket encounters; enter a name of an account or
a new name of an account to create one'''
if mudsys.account_exists(arg):
# logging on to an already existing account
mud.log_string("Account '" + arg + "' is trying to connect.")
acct = mudsys.load_account(arg)
# attach our account to our socket. Put in mudsys to prevent scripts
# from messing around with account and socket connections
mudsys.attach_account_socket(acct, sock)
sock.pop_ih()
sock.push_ih(acct_menu_handler, acct_main_menu)
sock.push_ih(acct_password_handler, acct_password_prompt)
elif not check_acct_name(arg):
sock.send(mud.format_string("That is an invalid account name. Your " \
"account name must only consist of " \
"characters and numbers, and it must be " \
"4 and 12 characters in length. The first "\
"character MUST be a letter. Please pick "\
"another.", False))
elif mudsys.account_creating(arg):
sock.send("An account with that name is already creating.")
else:
# creating a new account
mud.log_string("Account '" + arg + "' is trying to create.")
# create our new account
acct = mudsys.create_account(arg)
if acct == None:
sock.send("Could not create an account with that name.")
else:
mudsys.attach_account_socket(acct, sock)
sock.pop_ih()
sock.push_ih(acct_menu_handler, acct_main_menu)
sock.push_ih(acct_finish_handler, acct_finish_prompt)
sock.push_ih(acct_confirm_password_handler, acct_confirm_password_prompt)
sock.push_ih(acct_new_password_handler, acct_new_password_prompt)
def acct_new_password_handler(sock, arg):
'''asks a new account for a password'''
if len(arg) > 0:
# put in mudsys to prevent scripts from messing with passwords
mudsys.set_password(sock.account, arg)
sock.pop_ih()
def acct_confirm_password_handler(sock, arg):
'''checks to see if our argument matches our password; if not, we re-enter
our old password'''
# password functions put in mudsys to prevent scripts from
# messing with passwords
if not mudsys.password_matches(sock.account, arg):
sock.send("Passwords do not match.")
sock.pop_ih()
sock.push_ih(acct_confirm_password_handler,acct_confirm_password_prompt)
sock.push_ih(acct_password_handler, acct_password_prompt)
else:
# Password matches. Keep it and go down a level
sock.send_raw(unsquelch)
sock.pop_ih()
def acct_password_handler(sock, arg):
'''asks an account to verify its password'''
# password functions put in mudsys to prevent scripts from
# messing with passwords
sock.send_raw(unsquelch)
if not mudsys.password_matches(sock.account, arg):
sock.send("Incorrect password.")
sock.close()
else:
# password matches, pop our handler and go down a level
sock.pop_ih()
def find_reconnect(name):
'''searches through the character list for a PC whose name matches the
supplied name'''
name = name.lower()
for ch in char.char_list():
if ch.is_pc and name == ch.name.lower():
return ch
return None
def acct_load_char(sock, arg):
'''loads a character attached to the account. Argument supplied must be a
numeric value corresponding to the character'''
arg = int(arg)
if arg >= len(sock.account.characters()) or arg < 0:
sock.send("Invalid choice!")
else:
# get the name
name = sock.account.characters()[arg]
# first, try a reconnect
ch = find_reconnect(name)
# no reconnect? Try loading our character
if not ch == None:
# swap the sockets
old_sock = ch.sock
# attach and detach put in mudsys to prevent scripts from
# messing around with the connections between chars and sockets
mudsys.detach_char_socket(ch)
mudsys.attach_char_socket(ch, sock)
if old_sock != None:
old_sock.close()
mud.log_string(ch.name + " has reconnected.")
ch.send("You take over a body already in use.")
sock.push_ih(mudsys.handle_cmd_input, mudsys.show_prompt)
else:
# load our character. Put in mudsys to prevent scripts from using it
ch = mudsys.load_char(name)
if ch == None:
sock.send("The player file for " + name + " is missing.")
elif (mudsys.sys_getval("lockdown") != '' and
not ch.isInGroup(mudsys.sys_getval("lockdown"))):
sock.send("You are currently locked out of the mud.")
mud.extract(ch)
else:
# attach put in mudsys to prevent scripts from messing with
# character and socket links
mudsys.attach_char_socket(ch, sock)
if mudsys.try_enter_game(ch):
mud.log_string(ch.name + " has entered the game.")
sock.push_ih(mudsys.handle_cmd_input, mudsys.show_prompt)
ch.page(mud.get_motd())
ch.act("look")
hooks.run("enter", hooks.build_info("ch rm", (ch, ch.room)))
else:
sock.send("There was a problem entering the game. " + \
"try again later.")
# detach put in mudsys t prevent scripts from messing with
# character and socket links
mudsys.detach_char_socket(ch, sock)
mud.extract(ch)
def acct_menu_handler(sock, arg):
'''parses account commands (new character, enter game, quit, etc)'''
if len(arg) == 0:
return
arg = arg[0].upper()
if arg.isdigit():
acct_load_char(sock, arg)
elif arg == 'Q':
sock.send("Come back soon!")
mudsys.do_save(sock.account)
sock.close()
elif arg == 'P':
sock.push_ih(acct_confirm_password_handler,acct_confirm_password_prompt)
sock.push_ih(acct_new_password_handler, acct_new_password_prompt)
sock.push_ih(acct_password_handler, acct_password_prompt)
elif arg == 'N':
hooks.run("create_character", hooks.build_info("sk", (sock,)))
else:
sock.send("Invalid choice!")
def display_acct_chars(sock):
'''shows the socket a prettied list of characters tied to the account it
has attached. Prints three names per line.'''
num_cols = 3
print_room = (80 - 10*num_cols)/num_cols
fmt = " {c%2d{g) %-" + str(print_room) + "s"
sock.send("{w\r\nPlay a Character:")
i = 0
for ch in sock.account.characters():
sock.send_raw(fmt % (i, ch))
if i % num_cols == num_cols - 1:
sock.send_raw("\r\n")
i = i + 1
if not i % num_cols == 0:
sock.send_raw("\r\n")
def acct_main_menu(sock):
'''displays the main menu for the account and asks for a command'''
if len(sock.account.characters()) > 0:
display_acct_chars(sock)
sock.send("\r\n{wAdditional Options:")
sock.send(" {g[{cP{g]assword change")
sock.send(" {g[{cN{g]new character\r\n")
sock.send_raw("Enter choice, or Q to quit:{n ")
################################################################################
# events for blocking action when dns lookup is in progress
################################################################################
def dns_check_event(no_owner, unused, info):
sock, = hooks.parse_info(info)
if sock.can_use:
sock.send("Lookup complete.")
sock.pop_ih()
sock.bust_prompt()
else:
event.start_event(None, 0.1, dns_check_event, None, info)
################################################################################
# account handler hooks
################################################################################
def account_handler_hook(info):
# put a nonfunctional prompt up while waiting for the DNS to resolve
sock, = hooks.parse_info(info)
sock.push_ih(acct_name_handler, acct_name_prompt)
sock.push_ih(acct_wait_dns_handler, acct_wait_dns_prompt)
event.start_event(None, 0.1, dns_check_event, None, info)
def copyover_complete_hook(info):
sock, = hooks.parse_info(info)
sock.push_ih(acct_menu_handler, acct_main_menu)
sock.push_ih(mudsys.handle_cmd_input, mudsys.show_prompt)
################################################################################
# loading and unloading the module
################################################################################
hooks.add("receive_connection", account_handler_hook)
hooks.add("copyover_complete", copyover_complete_hook)
def __unload__():
'''removes the hooks for account handling'''
hooks.remove("receive_connection", account_handler_hook)
hooks.remove("copyover_complete", copyover_complete_hook)