''' 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, utils # 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 login_method_prompt(sock): sock.send_raw("Choose an option: ") def acct_new_password_prompt(sock): sock.send_raw("\r\nWhat is your new password? " + squelch) def acct_password_prompt(sock): sock.send_raw("What is your password? " + squelch) def acct_wait_dns_prompt(sock): sock.send_raw(" Resolving your internet address, please have patience... ") def try_create_account(sock, name, psswd): if mudsys.account_exists(name): return False elif mudsys.account_creating(name): return False elif not check_acct_name(name): return False else: # creating a new account mud.log_string("Account '" + name + "' is trying to create.") # create our new account acct = mudsys.create_account(name) if acct == None: return False else: mudsys.attach_account_socket(acct, sock) mudsys.set_password(acct, psswd) sock.pop_ih() sock.push_ih(acct_menu_handler, acct_main_menu) #sock.push_ih(acct_finish_handler, acct_finish_prompt) # log that the account created mud.log_string("New account '" + acct.name + "' has created.") # register and save the account to disk mudsys.do_register(acct) return True return False def try_load_account(sock, name, psswd): '''Attempt to load an account with the given name and password.''' if not mudsys.account_exists(name): return False else: acct = mudsys.load_account(name) if not mudsys.password_matches(acct, psswd): return False # successful load mudsys.attach_account_socket(acct, sock) sock.pop_ih() sock.push_ih(acct_menu_handler, acct_main_menu) return True return False def login_method_handler(sock, arg): args = arg.split() if len(args) == 0: return args[0] = args[0].lower() if "create".startswith(args[0]): if len(args) != 3: return elif mudsys.account_exists(args[1]): sock.send("{cAn account by that name already exists.{n\r\n") elif not check_acct_name(args[1]): txt = "{cThat 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.{n" sock.send(mud.format_string(txt, False)) elif not try_create_account(sock, args[1], args[2]): sock.send("Your account was unable to be created.") elif "load".startswith(args[0]): if len(args) != 3: return elif not try_load_account(sock, args[1], args[2]): sock.send("{cInvalid account name or password.{n\r\n") elif "guest".startswith(args[0]): if (mudsys.sys_getval("lockdown") != '' and not utils.is_keyword(mudsys.sys_getval("lockdown"), "player")): sock.send("{cThe mud is currently locked out to new players.{n\r\n") else: sock.pop_ih() hooks.run("create_guest", hooks.build_info("sk", (sock,))) def acct_wait_dns_handler(sock, arg): # do nothing return def acct_new_password_handler(sock, arg): '''asks a new account for a password''' sock.send_raw(unsquelch) 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_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, name): '''loads a character attached to the account. Argument supplied must be a name of the corresponding character''' chars = sock.account.characters() if not name.lower() in [n.lower() for n in sock.account.characters()]: sock.send("A character by that name does not exist on your account.") else: # 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.act("clear") ch.send("You take over a body already in use.") ch.act("look") hooks.run("reconnect", hooks.build_info("ch", (ch,))) sock.push_ih(mudsys.handle_cmd_input, mudsys.show_prompt, "playing") 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, "playing") # ch.act("clear") 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 args = arg.split() args[0] = args[0].upper() if args[0].isdigit(): opts = sock.account.characters() arg = int(args[0]) if arg < 0 or arg >= len(opts): sock.send("Invalid choice!") else: acct_load_char(sock, opts[arg]) elif args[0] == 'L': if len(args) == 1: sock.send("Which character would you like to load?") else: acct_load_char(sock, args[1]) elif args[0] == 'Q' or "QUIT".startswith(args[0]): sock.send("Come back soon!") mudsys.do_save(sock.account) sock.close() elif args[0] == '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 args[0] == 'N': if "player" in [x.strip() for x in mudsys.sys_getval("lockdown").split(",")]: sock.send("New characters are not allowed to be created at this time.") else: 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{n) %-" + 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''' line_buf = "%-38s" % " " # make the account menu look pretty img = ["+--------------------------------------+", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| I M A G E |", "| H E R E |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "| |", "+--------------------------------------+"] # the lines for displaying our account options opts = [ ] chars = sock.account.characters() chars.sort() if len(chars) > 0: opts.append(" {wPlay A Character: ") for i in range(len(chars)): opts.append(" {n[{c%1d{n] %-30s" % (i,chars[i])) opts.append(line_buf) # append our other displays opts.append(" {wAccount Management: ") opts.append(" {n[{cP{n]assword change ") opts.append(" {n[{cN{n]ew character ") opts.append(" {n[{cL{n]oad character <name> ") opts.append(line_buf) opts.append(line_buf) opts.append(line_buf) # fill up our height to be in line with the image while len(opts) < len(img) - 2: opts.insert(0, line_buf) # append our title opts.insert(1, " {nW E L C O M E T O ") opts.insert(2, " {nN A K E D M U D ") # display all of our info sock.send("") for i in range(max(len(opts), len(img))): if i < len(opts): sock.send_raw(opts[i]) else: sock.send_raw(line_buf) if i < len(img): sock.send_raw("{n%s" % img[i]) sock.send("") sock.send_raw("{nEnter choice, or Q to quit: ") ################################################################################ # events for blocking action when dns lookup is in progress ################################################################################ def dns_check_event(owner, void, info): '''After a socket connects, monitor their hostname until dns lookup is complete. Then, put the socket into the account handler. ''' sock, = hooks.parse_info(info) if sock != None and sock.can_use: sock.send(" Lookup complete.") sock.send("================================================================================") sock.send(mud.get_greeting()) sock.pop_ih() sock.bust_prompt() # mud.log_string("new connection from " + sock.hostname) else: event.start_event(None, 0.2, dns_check_event, None, info) ################################################################################ # account handler hooks ################################################################################ def account_handler_hook(info): '''When a socket connects, put them into the account handler menu.''' # put a nonfunctional prompt up while waiting for the DNS to resolve sock, = hooks.parse_info(info) sock.push_ih(login_method_handler, login_method_prompt) mud.log_string("new socket, %d, attempting to connect" % sock.uid) sock.send(mud.get_greeting()) sock.send("== Options Are ================================================================") sock.send(" Load account : load <account> <password>") sock.send(" Create account : create <account> <password>") sock.send(" Play as guest : guest") sock.send("===============================================================================") sock.send("") ''' sock.push_ih(acct_wait_dns_handler, acct_wait_dns_prompt) sock.send("================================================================================") event.start_event(None, 0.2, 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, "playing") ################################################################################ # 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)