# actual maximum length you want.
player_name_len 16
+# The maximum number of aliases a player may have simultaneously.
+# Setting this to 0 disables aliases. To allow an unlimited number
+# of aliases, set this to 4000 or so.
+max_aliases 3
+
# Limit the number of objects players can own.
use_quota yes
See also: leave, @lfail, @olfail, ACTION LISTS
& @alias
- @alias <player>=<alias>
-
- @alias is a special attribute. When a player sets an @alias, he is
- effectively giving himself a secondary name; he can be paged by his
- @alias, and matched with *<alias>, and all other game functions which
- look up player names will also accept the alias. The attribute is
- visible to all players.
-
- Aliases cannot be longer than the limit allowed for player names,
+ @alias <player>=<name>;<alias>[;<alias2>[;<alias3>[...]]]
+
+ @alias is a special attribute that lists a player's names; players
+ can be paged by their aliases, matched with *<alias>, and all other game
+ functions which look up player names will also accept an alias.
+ The attribute is visible to all players.
+
+ A list of aliases, separated by semicolons, may be provided.
+ Players should include their usual @name in the alias list, because
+ the @name command allows setting name to any alias in the list.
+ The number of aliases allowed in the list may be limited by
+ the game's administrators through the 'max_aliases' @config parameter.
+
+ If the page_aliases config directive is on, the first alias in the
+ list is returned along with the player's name.
+
+ Each alias cannot be longer than the limit allowed for player names,
cannot contain spaces, and must be unique -- no other player may
have the same alias or name as any other player's alias or name.
@alias has no effect on non-players.
+
+ See also: @name, alias(), fullalias()
& @allhalt
@allhalt
names, the name should be enclosed in quotes:
@name me = "James Bond"
+ Players can change their name to any name not in use by another
+ player; players may "reserve" a set of names for their use by
+ setting them in their @alias.
+
Changing the name of <object> will cause object to execute its
ONAME and ANAME. The old name will be passed at %0 to these;
the new name will be passed as %1.
+
+ See also: @alias
& @newpassword
@newpassword <player> = <password>
See "help @search3" for more.
& @search3
+ If <class>=MINDB, only objects with dbrefs of <restriction> or
+ higher will be listed. If <class>=MAXDB, only objects with dbrefs
+ of <restriction> or lower will be listed.
+
For the class TYPE=PLAYER, and for PLAYER=<player-name>, anyone may
obtain information on any player. In all other cases, only Directors may
obtain information about other players. This is computationally
@search Joe eval=1,100,200 <-- list objects from #100-#200 owned by Joe.
@search eval=gt(money(##),10) <-- list all objects owned by me
worth more than 10 coins.
-
+
See also: lsearch, lsearchr
& @select
@select <string>=<expr1>,<action1>[,<exprN>,<actionN>]...[,<default>]
/* delimiter for lists of exit aliases */
#define EXIT_DELIMITER ';'
+/* delimiter for lists of player name aliases */
+#define ALIAS_DELIMITER ';'
#define QUIT_COMMAND "QUIT"
#define WHO_COMMAND "WHO"
char ip_addr[64]; /**< What ip address should the server bind to? */
char ssl_ip_addr[64]; /**< What ip address should the server bind to? */
int player_name_spaces; /**< Can players have multiword names? */
+ int max_aliases; /**< Maximum allowed aliases per player */
int forking_dump; /**< Should we fork to dump? */
int restrict_building; /**< Is the builder power required to build? */
int free_objects; /**< If builder power is required, can you create without it? */
#define RESTRICTED_BUILDING (options.restrict_building)
#define NO_FORK (!options.forking_dump)
#define PLAYER_NAME_SPACES (options.player_name_spaces)
+#define MAX_ALIASES (options.max_aliases)
#define SAFER_UFUN (options.safer_ufun)
#define NOISY_WHISPER (options.noisy_whisper)
#define POSSESSIVE_GET (options.possessive_get)
/* From player.c */
extern int password_check(dbref player, const char *password);
extern dbref lookup_player(const char *name);
+extern dbref lookup_player_name(const char *name);
/* from player.c */
extern dbref create_player(const char *name, const char *password,
const char *host, const char *ip);
/* From plyrlist.c */
void clear_players(void);
-void add_player(dbref player, const char *alias);
+void add_player(dbref player);
+void add_player_alias(dbref player, const char *alias);
void delete_player(dbref player, const char *alias);
+void reset_player_list(dbref player, const char *oldname, const char *oldalias,
+ const char *name, const char *alias);
/* From predicat.c */
extern int pay_quota(dbref, int);
extern void change_quota(dbref who, int payment);
extern int ok_name(const char *name);
extern int ok_command_name(const char *name);
-extern int ok_player_name(const char *name, dbref player);
+extern int ok_player_name(const char *name, dbref player, dbref thing);
+extern int ok_player_alias(const char *alias, dbref player, dbref thing);
extern int ok_password(const char *password);
extern int ok_tag_attribute(dbref player, char *params);
extern dbref parse_match_possessor(dbref player, const char **str);
const char *check) __attribute_malloc__;
extern void mush_free(Malloc_t RESTRICT ptr, const char *RESTRICT check);
extern long get_random_long(long low, long high);
+ extern char *fullalias(dbref it);
+ extern char *shortalias(dbref it);
extern char *shortname(dbref it);
extern dbref absolute_room(dbref it);
int can_interact(dbref from, dbref to, int type);
upcasestr(name);
if (!strcmp(name, "ALIAS") && IsPlayer(thing)) {
old = atr_get_noparent(thing, "ALIAS");
+ tbuf1[0] = '\0';
if (old) {
/* Old alias - we're allowed to change to a different case */
strcpy(tbuf1, atr_value(old));
- if (s
- && (!*s
- || (strcasecmp(s, tbuf1) && !ok_player_name(s, player)))) {
+ if (s && (!*s || (strcasecmp(s, tbuf1)
+ && !ok_player_alias(s, player, thing)))) {
notify(player, T("That is not a valid alias."));
return -1;
}
- if (Can_Write_Attr(player, thing, old))
- delete_player(thing, tbuf1);
} else {
/* No old alias */
- if (s && *s && !ok_player_name(s, player)) {
+ if (s && *s && !ok_player_alias(s, player, thing)) {
notify(player, T("That is not a valid alias."));
return -1;
}
return 0;
}
if (!strcmp(name, "ALIAS") && IsPlayer(thing)) {
- if (s && *s) {
- add_player(thing, s);
+ reset_player_list(thing, NULL, tbuf1, NULL, s);
+ if (s && *s)
notify(player, T("Alias set."));
- } else {
+ else
notify(player, T("Alias removed."));
- }
return 1;
} else if (!strcmp(name, "LISTEN")) {
if (IsRoom(thing))
{"player_name_spaces", cf_bool, &options.player_name_spaces, 2, 0,
"cosmetic"}
,
+ {"max_aliases", cf_int, &options.max_aliases, -1, 0, "limits"}
+ ,
{"ansi_names", cf_bool, &options.ansi_names, 2, 0, "cosmetic"}
,
{"only_ascii_in_names", cf_bool, &options.ascii_names, 2, 0, "cosmetic"}
strcpy(options.ip_addr, "");
strcpy(options.ssl_ip_addr, "");
options.player_name_spaces = 0;
+ options.max_aliases = 3;
options.forking_dump = 1;
options.restrict_building = 0;
options.free_objects = 1;
}
/* check to see if it's a player */
if (IsPlayer(i)) {
- add_player(i, NULL);
+ add_player(i);
clear_flag_internal(i, "CONNECTED");
}
break;
i);
}
if (IsPlayer(i)) {
- add_player(i, NULL);
+ add_player(i);
clear_flag_internal(i, "CONNECTED");
}
}
add_folder_name(god, 0, "inbox");
#endif
PUSH(god, Contents(start_room));
- add_player(god, NULL);
+ add_player(god);
s_Pennies(god, START_BONUS);
local_data_create(god);
current_state.players++;
{"ACCNAME", fun_accname, 1, 1, FN_REG},
{"ADD", fun_add, 2, INT_MAX, FN_REG},
{"AFTER", fun_after, 2, 2, FN_REG},
+ {"ALIAS", fun_alias, 1, 2, FN_REG},
{"ALIGN", fun_align, 2, INT_MAX, FN_REG},
{"ALLOF", fun_allof, 2, INT_MAX, FN_NOPARSE},
{"ALPHAMAX", fun_alphamax, 1, INT_MAX, FN_REG},
{"FOREACH", fun_foreach, 2, 4, FN_REG},
{"FRACTION", fun_fraction, 1, 1, FN_REG},
{"FUNCTIONS", fun_functions, 0, 0, FN_REG},
+ {"FULLALIAS", fun_fullalias, 1, 1, FN_REG},
{"FULLNAME", fun_fullname, 1, 1, FN_REG},
{"GET", fun_get, 1, 1, FN_REG},
{"GET_EVAL", fun_get_eval, 1, 1, FN_REG},
}
}
+/* ARGSUSED */
+FUNCTION(fun_alias)
+{
+ dbref it;
+
+ it = match_thing(executor, args[0]);
+ if (!GoodObject(it))
+ safe_str(T(e_notvis), buff, bp);
+
+ /* Support changing alias via function if side-effects are enabled */
+ if (nargs == 2) {
+ if (!command_check_byname(executor, "ATTRIB_SET")
+ || fun->flags & FN_NOSIDEFX) {
+ safe_str(T(e_perm), buff, bp);
+ return;
+ }
+ if (!FUNCTION_SIDE_EFFECTS)
+ safe_str(T(e_disabled), buff, bp);
+ else
+ do_set_atr(it, "ALIAS", args[1], executor, 0);
+ return;
+ } else {
+ safe_str(shortalias(it), buff, bp);
+ }
+}
+
+/* ARGSUSED */
+FUNCTION(fun_fullalias)
+{
+ dbref it = match_thing(executor, args[0]);
+ if (GoodObject(it))
+ safe_str(fullalias(it), buff, bp);
+ else
+ safe_str(T(e_notvis), buff, bp);
+}
+
/* ARGSUSED */
FUNCTION(fun_name)
{
else if (!strcasecmp(args[0], "attrname"))
safe_boolean(good_atr_name(upcasestr(args[1])), buff, bp);
else if (!strcasecmp(args[0], "playername"))
- safe_boolean(ok_player_name(args[1], executor), buff, bp);
+ safe_boolean(ok_player_name(args[1], executor, executor), buff, bp);
else if (!strcasecmp(args[0], "password"))
safe_boolean(ok_password(args[1]), buff, bp);
else if (!strcasecmp(args[0], "command"))
bp = buf;
safe_str(atr_value(s), buf, &bp);
*bp = '\0';
- add_player(thing, buf);
+ add_player_alias(thing, buf);
}
}
}
gst_id = NOTHING;
strncpy(guest_name, T(GUEST_PREFIX), BUFFER_LEN-1);
strcat(guest_name, GUEST_NUMBER(i+1));
- if(ok_player_name(guest_name, NOTHING))
+ if(ok_player_name(guest_name, NOTHING, NOTHING))
break;
else if((gst_id = lookup_player(guest_name)) != NOTHING && !Connected(gst_id))
break;
const char *ip)
{
dbref player;
- if (!ok_player_name(name, NOTHING)) {
+ if (!ok_player_name(name, NOTHING, NOTHING)) {
do_log(LT_CONN, 0, 0, T("Failed creation (bad name) from %s"), host);
return NOTHING;
}
dbref player;
FILE *fp;
- if (!ok_player_name(name, NOTHING)) {
+ if (!ok_player_name(name, NOTHING, NOTHING)) {
do_log(LT_CONN, 0, 0, T("Failed registration (bad name) from %s"), host);
return NOTHING;
}
/* link him to PLAYER_START */
PUSH(player, Contents(PLAYER_START));
- add_player(player,NULL);
+ add_player(player);
add_lock(GOD, player, Basic_Lock, parse_boolexp(player, "=me", Basic_Lock),
-1);
add_lock(GOD, player, Enter_Lock, parse_boolexp(player, "=me", Basic_Lock),
#include "mushdb.h"
#include "dbdefs.h"
#include "flags.h"
+#include "attrib.h"
#include "htab.h"
#include "confmagic.h"
/** Add a player to the player list htab.
* \param player dbref of player to add.
- * \param alias name to use as hash table key for player, if given.
*/
void
-add_player(dbref player, const char *alias)
+add_player(dbref player)
{
long tmp;
tmp = player;
if (!hft_initialized)
init_hft();
- if (alias)
- hashadd(strupper(alias), (void *) tmp, &htab_player_list);
- else
- hashadd(strupper(Name(player)), (void *) tmp, &htab_player_list);
+ hashadd(strupper(Name(player)), (void *) tmp, &htab_player_list);
+}
+
+/** Add a player's alias list to the player list htab.
+ * \param player dbref of player to add.
+ * \param alias list of names ot use as hash table keys for player,
+ * semicolon-separated.
+ */
+void
+add_player_alias(dbref player, const char *alias)
+{
+ long tmp;
+ char tbuf1[BUFFER_LEN], *s, *sp;
+ if (!hft_initialized)
+ init_hft();
+ if (!alias) {
+ add_player(player);
+ return;
+ }
+ strncpy(tbuf1, alias, BUFFER_LEN - 1);
+ tbuf1[BUFFER_LEN - 1] = '\0';
+ s = trim_space_sep(tbuf1, ALIAS_DELIMITER);
+ while (s) {
+ sp = split_token(&s, ALIAS_DELIMITER);
+ while (sp && *sp && *sp == ' ')
+ sp++;
+ if (sp && *sp) {
+ tmp = player;
+ hashadd(strupper(sp), (void *) tmp, &htab_player_list);
+ }
+ }
}
/** Look up a player in the player list htab (or by dbref).
lookup_player(const char *name)
{
int p;
- void *hval;
- long tmp;
if (!name || !*name)
return NOTHING;
}
if (*name == LOOKUP_TOKEN)
name++;
+ return lookup_player_name(name);
+}
+
+/** Look up a player in the player list htab only.
+ * \param name name of player to find.
+ * \return dbref of player, or NOTHING.
+ */
+dbref
+lookup_player_name(const char *name)
+{
+ long tmp;
+ void *hval;
hval = hashfind(strupper(name), &htab_player_list);
if (!hval)
return NOTHING;
*/
}
+
/** Remove a player from the player list htab.
* \param player dbref of player to remove.
* \param alias key to remove if given.
void
delete_player(dbref player, const char *alias)
{
- if (alias)
- hashdelete(strupper(alias), &htab_player_list);
- else
+ if (!hft_initialized) {
+ init_hft();
+ return;
+ }
+ if (alias) {
+ /* This could be a compound alias, in which case we need to delete
+ * them all, but we shouldn't delete the player's own name!
+ */
+ char tbuf1[BUFFER_LEN], *s, *sp;
+ strncpy(tbuf1, alias, BUFFER_LEN - 1);
+ tbuf1[BUFFER_LEN - 1] = '\0';
+ s = trim_space_sep(tbuf1, ALIAS_DELIMITER);
+ while (s) {
+ sp = split_token(&s, ALIAS_DELIMITER);
+ while (sp && *sp && *sp == ' ')
+ sp++;
+ if (sp && *sp && strcasecmp(sp, Name(player)))
+ hashdelete(strupper(sp), &htab_player_list);
+ }
+ } else
hashdelete(strupper(Name(player)), &htab_player_list);
}
+
+/** Reset all of a player's player list entries (names/aliases).
+ * This is called when a player changes name or alias.
+ * We remove all their old entries, and add back their new ones.
+ * \param player dbref of player
+ * \param oldname player's former name (NULL if not changing)
+ * \param oldalias player's former aliases (NULL if not changing)
+ * \param name player's new name
+ * \param alias player's new aliases
+ */
+void
+reset_player_list(dbref player, const char *oldname, const char *oldalias,
+ const char *name, const char *alias)
+{
+ char tbuf1[BUFFER_LEN];
+ char tbuf2[BUFFER_LEN];
+ if (!oldname) {
+ oldname = Name(player);
+ name = Name(player);
+ }
+ if (oldalias) {
+ strncpy(tbuf1, oldalias, BUFFER_LEN - 1);
+ tbuf1[BUFFER_LEN - 1] = '\0';
+ if (alias) {
+ strncpy(tbuf2, alias, BUFFER_LEN - 1);
+ tbuf2[BUFFER_LEN - 1] = '\0';
+ } else {
+ tbuf2[0] = '\0';
+ }
+ } else {
+ /* We are not changing aliases, just name, but we need to get the
+ * aliases anyway, since we may change name to something that's
+ * in the alias, and thus must not be deleted.
+ */
+ ATTR *a = atr_get_noparent(player, "ALIAS");
+ if (a) {
+ strncpy(tbuf1, atr_value(a), BUFFER_LEN - 1);
+ tbuf1[BUFFER_LEN - 1] = '\0';
+ } else {
+ tbuf1[0] = '\0';
+ }
+ strcpy(tbuf2, tbuf1);
+ }
+ /* Delete all the old stuff */
+ delete_player(player, tbuf1);
+ delete_player(player, NULL);
+ /* Add in the new stuff */
+ add_player_alias(player, name);
+ add_player_alias(player, tbuf2);
+}
&& strcasecmp((char *) name, "here"));
}
-/** Is a name a valid player name?
+/** Is a name a valid player name when applied by player to thing?
* Player names must be valid object names, but also not forbidden (unless
* the player is a wizard). They are
* subject to a different length limit, and subject to more stringent
* restrictions on valid characters. Finally, it can't be the same as
- * an existing player name or alias.
+ * an existing player name or alias unless it's one of theirs.
* \param name name to check.
* \param player player for permission checks.
+ * \param thing player who will get the name.
* \retval 1 name is valid for players.
* \retval 0 name is not valid for players.
*/
int
-ok_player_name(const char *name, dbref player)
+ok_player_name(const char *name, dbref player, dbref thing)
{
const unsigned char *scan, *good;
+ dbref lookup;
if (!ok_name(name)
|| (forbidden_name(name) && !(GoodObject(player) && Director(player)))
return 0;
}
- return (lookup_player(name) == NOTHING);
+ lookup = lookup_player(name);
+ return ((lookup == NOTHING) || (lookup == thing));
}
+
+/** Is a alias a valid player alias-list for thing?
+ * It must be a semicolon-separated list of valid player names
+ * with no more than than MAX_ALIASES names, if the player isn't
+ * a wizard.
+ * \param alias list to check.
+ * \param player player for permission checks.
+ * \param thing player who is being aliased.
+ * \retval 1 alias is valid for players.
+ * \retval 0 alias is not valid for players.
+ */
+int
+ok_player_alias(const char *alias, dbref player, dbref thing)
+{
+ char tbuf1[BUFFER_LEN], *s, *sp;
+ int cnt = 0;
+
+ if (!alias || !*alias)
+ return 0;
+
+ strncpy(tbuf1, alias, BUFFER_LEN - 1);
+ tbuf1[BUFFER_LEN - 1] = '\0';
+ s = trim_space_sep(tbuf1, ALIAS_DELIMITER);
+ while (s) {
+ sp = split_token(&s, ALIAS_DELIMITER);
+ while (sp && *sp && *sp == ' ')
+ sp++;
+ if (!sp || !*sp)
+ return 0; /* No null aliases */
+ if (!ok_player_name(sp, player, thing))
+ return 0;
+ cnt++;
+ }
+ return ((cnt <= MAX_ALIASES) || Director(player));
+}
+
+
/** Is a password acceptable?
* Acceptable passwords must be non-null and must contain only
* printable characters and no whitespace.
password++;
}
}
- if (strcasecmp(newname, Name(thing))
- && !ok_player_name(newname, thing)) {
- /* strcasecmp allows changing foo to Foo, etc. */
+ if (!ok_player_name(newname, player, thing)) {
notify(player, T("You can't give a player that name."));
return;
}
myenv[i] = NULL;
if (IsPlayer(thing))
- delete_player(thing, NULL);
+ reset_player_list(thing, Name(thing), NULL, newname, NULL);
set_name(thing, newname);
if(!IsPlayer(thing)) {
char lmbuf[1024];
set_lmod(thing, lmbuf);
}
if (IsPlayer(thing))
- add_player(thing, NULL);
+ add_player(thing);
if (!AreQuiet(player, thing))
notify(player, T("Name set."));
int fails_lock;
int is_haven;
ATTR *a;
+ char *alias;
tp2 = tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string");
if (!tbuf2)
}
/* Figure out the 'name' of the player */
- if (PAGE_ALIASES && (a = atr_get_noparent(player, "ALIAS")))
- current = tprintf("%s (%s)", Name(player), atr_value(a));
+ if (PAGE_ALIASES && (alias = shortalias(player)) && *alias)
+ current = tprintf("%s (%s)", Name(player), alias);
else
current = (char *) Name(player);
return low + (n % x);
}
+/** Return an object's alias. We expect a valid object.
+ * \param it dbref of object.
+ * \return object's complete alias.
+ */
+char *
+fullalias(dbref it)
+{
+ static char n[BUFFER_LEN]; /* STATIC */
+ ATTR *a = atr_get_noparent(it, "ALIAS");
+
+ if (!a)
+ return '\0';
+
+ strncpy(n, atr_value(a), BUFFER_LEN - 1);
+ n[BUFFER_LEN - 1] = '\0';
+
+ return n;
+}
+
+/** Return only the first component of an object's alias. We expect
+ * a valid object.
+ * \param it dbref of object.
+ * \return object's short alias.
+ */
+char *
+shortalias(dbref it)
+{
+ static char n[BUFFER_LEN]; /* STATIC */
+ char *s;
+
+ s = fullalias(it);
+ if (!(s && *s))
+ return '\0';
+
+ strncpy(n, s, BUFFER_LEN - 1);
+ n[BUFFER_LEN - 1] = '\0';
+ if ((s = strchr(n, ';')))
+ *s = '\0';
+
+ return n;
+}
+
/** Return an object's name, but for exits, return just the first
* component. We expect a valid object.
* \param it dbref of object.
FUNCTION_PROTO(fun_acos);
FUNCTION_PROTO(fun_add);
FUNCTION_PROTO(fun_after);
+FUNCTION_PROTO(fun_alias);
FUNCTION_PROTO(fun_align);
FUNCTION_PROTO(fun_allof);
FUNCTION_PROTO(fun_alphamax);
FUNCTION_PROTO(fun_following);
FUNCTION_PROTO(fun_foreach);
FUNCTION_PROTO(fun_fraction);
+FUNCTION_PROTO(fun_fullalias);
FUNCTION_PROTO(fun_fullname);
FUNCTION_PROTO(fun_functions);
FUNCTION_PROTO(fun_get);