mux/src/player.cpp

Go to the documentation of this file.
00001 // player.cpp
00002 //
00003 // $Id: player.cpp,v 1.36 2006/01/07 09:14:26 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include "attrs.h"
00012 #include "command.h"
00013 #include "comsys.h"
00014 #include "functions.h"
00015 #include "interface.h"
00016 #include "powers.h"
00017 #include "svdreport.h"
00018 #include "sha1.h"
00019 
00020 #define NUM_GOOD    4   // # of successful logins to save data for.
00021 #define NUM_BAD     3   // # of failed logins to save data for.
00022 
00023 typedef struct hostdtm HOSTDTM;
00024 struct hostdtm
00025 {
00026     char *host;
00027     char *dtm;
00028 };
00029 
00030 typedef struct logindata LDATA;
00031 struct logindata
00032 {
00033     HOSTDTM good[NUM_GOOD];
00034     HOSTDTM bad[NUM_BAD];
00035     int tot_good;
00036     int tot_bad;
00037     int new_bad;
00038 };
00039 
00040 
00041 /* ---------------------------------------------------------------------------
00042  * decrypt_logindata, encrypt_logindata: Decode and encode login info.
00043  */
00044 
00045 static void decrypt_logindata(char *atrbuf, LDATA *info)
00046 {
00047     int i;
00048 
00049     info->tot_good = 0;
00050     info->tot_bad = 0;
00051     info->new_bad = 0;
00052     for (i = 0; i < NUM_GOOD; i++)
00053     {
00054         info->good[i].host = NULL;
00055         info->good[i].dtm = NULL;
00056     }
00057     for (i = 0; i < NUM_BAD; i++)
00058     {
00059         info->bad[i].host = NULL;
00060         info->bad[i].dtm = NULL;
00061     }
00062 
00063     if (*atrbuf == '#')
00064     {
00065         atrbuf++;
00066         info->tot_good = mux_atol(grabto(&atrbuf, ';'));
00067         for (i = 0; i < NUM_GOOD; i++)
00068         {
00069             info->good[i].host = grabto(&atrbuf, ';');
00070             info->good[i].dtm = grabto(&atrbuf, ';');
00071         }
00072         info->new_bad = mux_atol(grabto(&atrbuf, ';'));
00073         info->tot_bad = mux_atol(grabto(&atrbuf, ';'));
00074         for (i = 0; i < NUM_BAD; i++)
00075         {
00076             info->bad[i].host = grabto(&atrbuf, ';');
00077             info->bad[i].dtm = grabto(&atrbuf, ';');
00078         }
00079     }
00080 }
00081 
00082 static void encrypt_logindata(char *atrbuf, LDATA *info)
00083 {
00084     // Make sure the SPRINTF call tracks NUM_GOOD and NUM_BAD for the number
00085     // of host/dtm pairs of each type.
00086     //
00087     char nullc = '\0';
00088     int i;
00089     for (i = 0; i < NUM_GOOD; i++)
00090     {
00091         if (!info->good[i].host)
00092             info->good[i].host = &nullc;
00093         if (!info->good[i].dtm)
00094             info->good[i].dtm = &nullc;
00095     }
00096     for (i = 0; i < NUM_BAD; i++)
00097     {
00098         if (!info->bad[i].host)
00099             info->bad[i].host = &nullc;
00100         if (!info->bad[i].dtm)
00101             info->bad[i].dtm = &nullc;
00102     }
00103     char *bp = alloc_lbuf("encrypt_logindata");
00104     sprintf(bp, "#%d;%s;%s;%s;%s;%s;%s;%s;%s;%d;%d;%s;%s;%s;%s;%s;%s;",
00105         info->tot_good,
00106         info->good[0].host, info->good[0].dtm,
00107         info->good[1].host, info->good[1].dtm,
00108         info->good[2].host, info->good[2].dtm,
00109         info->good[3].host, info->good[3].dtm,
00110         info->new_bad, info->tot_bad,
00111         info->bad[0].host, info->bad[0].dtm,
00112         info->bad[1].host, info->bad[1].dtm,
00113         info->bad[2].host, info->bad[2].dtm);
00114     strcpy(atrbuf, bp);
00115     free_lbuf(bp);
00116 }
00117 
00118 /* ---------------------------------------------------------------------------
00119  * record_login: Record successful or failed login attempt.
00120  * If successful, report last successful login and number of failures since
00121  * last successful login.
00122  */
00123 
00124 void record_login
00125 (
00126     dbref player,
00127     bool  isgood,
00128     char  *ldate,
00129     char  *lhost,
00130     char  *lusername,
00131     char  *lipaddr
00132 )
00133 {
00134     LDATA login_info;
00135     dbref aowner;
00136     int aflags, i;
00137 
00138     char *atrbuf = atr_get(player, A_LOGINDATA, &aowner, &aflags);
00139     decrypt_logindata(atrbuf, &login_info);
00140     if (isgood)
00141     {
00142         if (login_info.new_bad > 0)
00143         {
00144             notify(player, "");
00145             notify(player, tprintf("**** %d failed connect%s since your last successful connect. ****",
00146                 login_info.new_bad, (login_info.new_bad == 1 ? "" : "s")));
00147             notify(player, tprintf("Most recent attempt was from %s on %s.",
00148                 login_info.bad[0].host, login_info.bad[0].dtm));
00149             notify(player, "");
00150             login_info.new_bad = 0;
00151         }
00152         if (  login_info.good[0].host
00153            && *login_info.good[0].host
00154            && login_info.good[0].dtm
00155            && *login_info.good[0].dtm)
00156         {
00157             notify(player, tprintf("Last connect was from %s on %s.",
00158                 login_info.good[0].host, login_info.good[0].dtm));
00159         }
00160 
00161         for (i = NUM_GOOD - 1; i > 0; i--)
00162         {
00163             login_info.good[i].dtm = login_info.good[i - 1].dtm;
00164             login_info.good[i].host = login_info.good[i - 1].host;
00165         }
00166         login_info.good[0].dtm = ldate;
00167         login_info.good[0].host = lhost;
00168         login_info.tot_good++;
00169         if (*lusername)
00170         {
00171             atr_add_raw(player, A_LASTSITE, tprintf("%s@%s", lusername, lhost));
00172         }
00173         else
00174         {
00175             atr_add_raw(player, A_LASTSITE, lhost);
00176         }
00177 
00178         // Add the players last IP too.
00179         //
00180         atr_add_raw(player, A_LASTIP, lipaddr);
00181     }
00182     else
00183     {
00184         for (i = NUM_BAD - 1; i > 0; i--)
00185         {
00186             login_info.bad[i].dtm = login_info.bad[i - 1].dtm;
00187             login_info.bad[i].host = login_info.bad[i - 1].host;
00188         }
00189         login_info.bad[0].dtm = ldate;
00190         login_info.bad[0].host = lhost;
00191         login_info.tot_bad++;
00192         login_info.new_bad++;
00193     }
00194     encrypt_logindata(atrbuf, &login_info);
00195     atr_add_raw(player, A_LOGINDATA, atrbuf);
00196     free_lbuf(atrbuf);
00197 }
00198 
00199 const char Base64Table[65] =
00200     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00201 
00202 #define ENCODED_LENGTH(x) ((((x)+2)/3)*4)
00203 
00204 static void EncodeBase64(size_t nIn, const char *pIn, char *pOut)
00205 {
00206     size_t nTriples  = nIn/3;
00207     size_t nLeftover = nIn%3;
00208     UINT32 stage;
00209 
00210     const UINT8 *p = (const UINT8 *)pIn;
00211           UINT8 *q = (      UINT8 *)pOut;
00212 
00213     while (nTriples--)
00214     {
00215         stage = (p[0] << 16) | (p[1] << 8) | p[2];
00216 
00217         q[0] = Base64Table[(stage >> 18)       ];
00218         q[1] = Base64Table[(stage >> 12) & 0x3F];
00219         q[2] = Base64Table[(stage >>  6) & 0x3F];
00220         q[3] = Base64Table[(stage      ) & 0x3F];
00221 
00222         q += 4;
00223         p += 3;
00224     }
00225 
00226     switch (nLeftover)
00227     {
00228     case 1:
00229         stage = p[0] << 16;
00230 
00231         q[0] = Base64Table[(stage >> 18)       ];
00232         q[1] = Base64Table[(stage >> 12) & 0x3F];
00233         q[2] = '=';
00234         q[3] = '=';
00235 
00236         q += 4;
00237         break;
00238 
00239     case 2:
00240         stage = (p[0] << 16) | (p[1] << 8);
00241 
00242         q[0] = Base64Table[(stage >> 18)       ];
00243         q[1] = Base64Table[(stage >> 12) & 0x3F];
00244         q[2] = Base64Table[(stage >>  6) & 0x3F];
00245         q[3] = '=';
00246 
00247         q += 4;
00248         break;
00249     }
00250     q[0] = '\0';
00251 }
00252 
00253 #define SHA1_PREFIX_LENGTH 6
00254 const char szSHA1Prefix[SHA1_PREFIX_LENGTH+1] = "$SHA1$";
00255 #define ENCODED_HASH_LENGTH ENCODED_LENGTH(5*sizeof(UINT32))
00256 
00257 #define MD5_PREFIX_LENGTH 3
00258 const char szMD5Prefix[MD5_PREFIX_LENGTH+1] = "$1$";
00259 
00260 #define BLOWFISH_PREFIX_LENGTH 4
00261 const char szBlowfishPrefix[BLOWFISH_PREFIX_LENGTH+1] = "$2a$";
00262 
00263 #define SALT_LENGTH 9
00264 #define ENCODED_SALT_LENGTH ENCODED_LENGTH(SALT_LENGTH)
00265 
00266 static const char *GenerateSalt(void)
00267 {
00268     char szSaltRaw[SALT_LENGTH+1];
00269     int i;
00270     for (i = 0; i < SALT_LENGTH; i++)
00271     {
00272         szSaltRaw[i] = (char)RandomINT32(0, 255);
00273     }
00274     szSaltRaw[SALT_LENGTH] = '\0';
00275 
00276     static char szSaltEncoded[SHA1_PREFIX_LENGTH + ENCODED_SALT_LENGTH+1];
00277     strcpy(szSaltEncoded, szSHA1Prefix);
00278     EncodeBase64(SALT_LENGTH, szSaltRaw, szSaltEncoded + SHA1_PREFIX_LENGTH);
00279     return szSaltEncoded;
00280 }
00281 
00282 void ChangePassword(dbref player, const char *szPassword)
00283 {
00284     int iType;
00285     s_Pass(player, mux_crypt(szPassword, GenerateSalt(), &iType));
00286 }
00287 
00288 #define CRYPT_FAIL        0
00289 #define CRYPT_SHA1        1
00290 #define CRYPT_MD5         2
00291 #define CRYPT_DES         3
00292 #define CRYPT_DES_EXT     4
00293 #define CRYPT_BLOWFISH    5
00294 #define CRYPT_CLEARTEXT   6
00295 #define CRYPT_OTHER       7
00296 
00297 const char szFail[] = "$FAIL$$";
00298 
00299 // REMOVE: After 2006-JUL-23, remove support for DES-encrypted passwords on
00300 // Win32 build.  This should allow support for DES-encrypted passwords to
00301 // strattle three distinct versions of MUX.  After that, to convert the older
00302 // passwords automatically would require going through one of these three
00303 // older versions of the server.  Alternatively, since crypt and DES-encrypted
00304 // passwords should be supported on Unix for even longer, converting the
00305 // flatfile on a Unix box remains an option.
00306 //
00307 const char *mux_crypt(const char *szPassword, const char *szSetting, int *piType)
00308 {
00309     const char *pSaltField = NULL;
00310     size_t nSaltField = 0;
00311 
00312     *piType = CRYPT_FAIL;
00313 
00314     if (szSetting[0] == '$')
00315     {
00316         const char *p = strchr(szSetting+1, '$');
00317         if (p)
00318         {
00319             p++;
00320             size_t nAlgo = p - szSetting;
00321             if (  nAlgo == SHA1_PREFIX_LENGTH
00322                && memcmp(szSetting, szSHA1Prefix, SHA1_PREFIX_LENGTH) == 0)
00323             {
00324                 // SHA-1
00325                 //
00326                 pSaltField = p;
00327                 p = strchr(pSaltField, '$');
00328                 if (p)
00329                 {
00330                     nSaltField = p - pSaltField;
00331                 }
00332                 else
00333                 {
00334                     nSaltField = strlen(pSaltField);
00335                 }
00336                 if (nSaltField <= ENCODED_SALT_LENGTH)
00337                 {
00338                     *piType = CRYPT_SHA1;
00339                 }
00340             }
00341             else if (  nAlgo == MD5_PREFIX_LENGTH
00342                     && memcmp(szSetting, szMD5Prefix, MD5_PREFIX_LENGTH) == 0)
00343             {
00344                 *piType = CRYPT_MD5;
00345             }
00346             else if (  nAlgo == BLOWFISH_PREFIX_LENGTH
00347                     && memcmp(szSetting, szBlowfishPrefix, BLOWFISH_PREFIX_LENGTH) == 0)
00348             {
00349                 *piType = CRYPT_BLOWFISH;
00350             }
00351             else
00352             {
00353                 *piType = CRYPT_OTHER;
00354             }
00355         }
00356     }
00357     else if (szSetting[0] == '_')
00358     {
00359         *piType = CRYPT_DES_EXT;
00360     }
00361     else
00362     {
00363 #if 0
00364         // Strictly speaking, we can say the algorithm is DES.
00365         //
00366         *piType = CRYPT_DES;
00367 #else
00368         // However, in order to support clear-text passwords, we restrict
00369         // ourselves to only verifying an existing DES-encrypted password and
00370         // we assume a fixed salt of 'XX'.  If you have been using a different
00371         // salt, or if you need to generate a DES-encrypted password, the
00372         // following code won't work.
00373         //
00374         size_t nSetting = strlen(szSetting);
00375         if (  nSetting == 13
00376            && memcmp(szSetting, "XX", 2) == 0)
00377         {
00378             *piType = CRYPT_DES;
00379         }
00380         else
00381         {
00382             *piType = CRYPT_CLEARTEXT;
00383         }
00384 #endif
00385     }
00386 
00387     switch (*piType)
00388     {
00389     case CRYPT_FAIL:
00390         return szFail;
00391 
00392     case CRYPT_CLEARTEXT:
00393         return szPassword;
00394 
00395     case CRYPT_MD5:
00396     case CRYPT_BLOWFISH:
00397     case CRYPT_OTHER:
00398     case CRYPT_DES_EXT:
00399 #ifdef WIN32
00400         // The WIN32 release only supports SHA1, DES, and clear-text.
00401         //
00402         return szFail;
00403 #endif // WIN32
00404 
00405     case CRYPT_DES:
00406 #if defined(HAVE_LIBCRYPT) \
00407  || defined(HAVE_CRYPT)
00408         return crypt(szPassword, szSetting);
00409 #else
00410         return szFail;
00411 #endif
00412     }
00413 
00414     // Calculate SHA-1 Hash.
00415     //
00416     SHA1_CONTEXT shac;
00417 
00418     SHA1_Init(&shac);
00419     SHA1_Compute(&shac, nSaltField, pSaltField);
00420     SHA1_Compute(&shac, strlen(szPassword), szPassword);
00421     SHA1_Final(&shac);
00422 
00423     // Serialize 5 UINT32 words into big-endian.
00424     //
00425     char szHashRaw[21];
00426     char *p = szHashRaw;
00427 
00428     int i;
00429     for (i = 0; i <= 4; i++)
00430     {
00431         *p++ = (UINT8)(shac.H[i] >> 24);
00432         *p++ = (UINT8)(shac.H[i] >> 16);
00433         *p++ = (UINT8)(shac.H[i] >>  8);
00434         *p++ = (UINT8)(shac.H[i]      );
00435     }
00436     *p = '\0';
00437 
00438     //          1         2         3         4
00439     // 12345678901234567890123456789012345678901234567
00440     // $SHA1$ssssssssssss$hhhhhhhhhhhhhhhhhhhhhhhhhhhh
00441     //
00442     static char buf[SHA1_PREFIX_LENGTH + ENCODED_SALT_LENGTH + 1 + ENCODED_HASH_LENGTH + 1 + 16];
00443     strcpy(buf, szSHA1Prefix);
00444     memcpy(buf + SHA1_PREFIX_LENGTH, pSaltField, nSaltField);
00445     buf[SHA1_PREFIX_LENGTH + nSaltField] = '$';
00446     EncodeBase64(20, szHashRaw, buf + SHA1_PREFIX_LENGTH + nSaltField + 1);
00447     return buf;
00448 }
00449 
00450 /* ---------------------------------------------------------------------------
00451  * check_pass: Test a password to see if it is correct.
00452  */
00453 
00454 static bool check_pass(dbref player, const char *pPassword)
00455 {
00456     bool bValidPass  = false;
00457     int  iType;
00458 
00459     int   aflags;
00460     dbref aowner;
00461     char *pTarget = atr_get(player, A_PASS, &aowner, &aflags);
00462     if (*pTarget)
00463     {
00464         if (strcmp(mux_crypt(pPassword, pTarget, &iType), pTarget) == 0)
00465         {
00466             bValidPass = true;
00467             if (iType != CRYPT_SHA1)
00468             {
00469                 ChangePassword(player, pPassword);
00470             }
00471         }
00472     }
00473 #if 0
00474     else if (GOD == player)
00475     {
00476         // When GOD doesn't have a password, we need to a way to set one.
00477         //
00478         bValidPass = true;
00479         ChangePassword(player, pPassword);
00480     }
00481 #endif
00482     free_lbuf(pTarget);
00483     return bValidPass;
00484 }
00485 
00486 /* ---------------------------------------------------------------------------
00487  * connect_player: Try to connect to an existing player.
00488  */
00489 
00490 dbref connect_player(char *name, char *password, char *host, char *username, char *ipaddr)
00491 {
00492     CLinearTimeAbsolute ltaNow;
00493     ltaNow.GetLocal();
00494     char *time_str = ltaNow.ReturnDateString(7);
00495 
00496     dbref player = lookup_player(NOTHING, name, false);
00497     if (player == NOTHING)
00498     {
00499         return NOTHING;
00500     }
00501     if (!check_pass(player, password))
00502     {
00503         record_login(player, false, time_str, host, username, ipaddr);
00504         return NOTHING;
00505     }
00506 
00507     // Compare to last connect see if player gets salary.
00508     //
00509     int aflags;
00510     dbref aowner;
00511     char *player_last = atr_get(player, A_LAST, &aowner, &aflags);
00512     if (strncmp(player_last, time_str, 10) != 0)
00513     {
00514         char *allowance = atr_pget(player, A_ALLOWANCE, &aowner, &aflags);
00515         if (*allowance == '\0')
00516         {
00517             giveto(player, mudconf.paycheck);
00518         }
00519         else
00520         {
00521             giveto(player, mux_atol(allowance));
00522         }
00523         free_lbuf(allowance);
00524     }
00525     free_lbuf(player_last);
00526     atr_add_raw(player, A_LAST, time_str);
00527     return player;
00528 }
00529 
00530 void AddToPublicChannel(dbref player)
00531 {
00532     if (  mudconf.public_channel[0] != '\0'
00533        && mudconf.public_channel_alias[0] != '\0')
00534     {
00535         do_addcom(player, player, player, 0, 2,
00536             mudconf.public_channel_alias, mudconf.public_channel);
00537     }
00538 }
00539 
00540 /* ---------------------------------------------------------------------------
00541  * create_player: Create a new player.
00542  */
00543 
00544 dbref create_player
00545 (
00546     char *name,
00547     char *password,
00548     dbref creator,
00549     bool isrobot,
00550     const char **pmsg
00551 )
00552 {
00553     *pmsg = NULL;
00554 
00555     // Potentially throttle the rate of player creation.
00556     //
00557     if (ThrottlePlayerCreate())
00558     {
00559         *pmsg = "The limit of new players for this hour has been reached. Please try again later.";
00560         return NOTHING;
00561     }
00562 
00563     // Make sure the password is OK.  Name is checked in create_obj.
00564     //
00565     char *pbuf = trim_spaces(password);
00566     if (!ok_password(pbuf, pmsg))
00567     {
00568         free_lbuf(pbuf);
00569         return NOTHING;
00570     }
00571 
00572     // If so, go create him.
00573     //
00574     dbref player = create_obj(creator, TYPE_PLAYER, name, isrobot);
00575     if (player == NOTHING)
00576     {
00577         *pmsg = "Either there is already a player with that name, or that name is illegal.";
00578         free_lbuf(pbuf);
00579         return NOTHING;
00580     }
00581 
00582     // Initialize everything.
00583     //
00584     ChangePassword(player, pbuf);
00585     s_Home(player, start_home());
00586     free_lbuf(pbuf);
00587     local_data_create(player);
00588     return player;
00589 }
00590 
00591 /* ---------------------------------------------------------------------------
00592  * do_password: Change the password for a player
00593  */
00594 
00595 void do_password
00596 (
00597     dbref executor,
00598     dbref caller,
00599     dbref enactor,
00600     int   key,
00601     int   nargs,
00602     char *oldpass,
00603     char *newpass
00604 )
00605 {
00606     UNUSED_PARAMETER(caller);
00607     UNUSED_PARAMETER(enactor);
00608     UNUSED_PARAMETER(key);
00609     UNUSED_PARAMETER(nargs);
00610 
00611     dbref aowner;
00612     int   aflags;
00613     char *target = atr_get(executor, A_PASS, &aowner, &aflags);
00614     const char *pmsg;
00615     if (  !*target
00616        || !check_pass(executor, oldpass))
00617     {
00618         notify(executor, "Sorry.");
00619     }
00620     else if (ok_password(newpass, &pmsg))
00621     {
00622         ChangePassword(executor, newpass);
00623         notify(executor, "Password changed.");
00624     }
00625     else
00626     {
00627         notify(executor, pmsg);
00628     }
00629     free_lbuf(target);
00630 }
00631 
00632 /* ---------------------------------------------------------------------------
00633  * do_last: Display login history data.
00634  */
00635 
00636 static void disp_from_on(dbref player, char *dtm_str, char *host_str)
00637 {
00638     if (dtm_str && *dtm_str && host_str && *host_str)
00639     {
00640         notify(player,
00641                tprintf("     From: %s   On: %s", dtm_str, host_str));
00642     }
00643 }
00644 
00645 void do_last(dbref executor, dbref caller, dbref enactor, int key, char *who)
00646 {
00647     UNUSED_PARAMETER(caller);
00648     UNUSED_PARAMETER(enactor);
00649     UNUSED_PARAMETER(key);
00650 
00651     dbref target, aowner;
00652     int i, aflags;
00653 
00654     if (  !who
00655        || !*who)
00656     {
00657         target = Owner(executor);
00658     }
00659     else if (string_compare(who, "me") == 0)
00660     {
00661         target = Owner(executor);
00662     }
00663     else
00664     {
00665         target = lookup_player(executor, who, true);
00666     }
00667 
00668     if (target == NOTHING)
00669     {
00670         notify(executor, "I couldn't find that player.");
00671     }
00672     else if (!Controls(executor, target))
00673     {
00674         notify(executor, NOPERM_MESSAGE);
00675     }
00676     else
00677     {
00678         char *atrbuf = atr_get(target, A_LOGINDATA, &aowner, &aflags);
00679         LDATA login_info;
00680         decrypt_logindata(atrbuf, &login_info);
00681 
00682         notify(executor, tprintf("Total successful connects: %d", login_info.tot_good));
00683         for (i = 0; i < NUM_GOOD; i++)
00684         {
00685             disp_from_on(executor, login_info.good[i].host, login_info.good[i].dtm);
00686         }
00687         notify(executor, tprintf("Total failed connects: %d", login_info.tot_bad));
00688         for (i = 0; i < NUM_BAD; i++)
00689         {
00690             disp_from_on(executor, login_info.bad[i].host, login_info.bad[i].dtm);
00691         }
00692         free_lbuf(atrbuf);
00693     }
00694 }
00695 
00696 /* ---------------------------------------------------------------------------
00697  * add_player_name, delete_player_name, lookup_player:
00698  * Manage playername->dbref mapping
00699  */
00700 
00701 bool add_player_name(dbref player, const char *name)
00702 {
00703     bool stat;
00704     char *temp, *tp;
00705 
00706     // Convert to all lowercase.
00707     //
00708     tp = temp = alloc_lbuf("add_player_name");
00709     safe_str(name, temp, &tp);
00710     *tp = '\0';
00711     mux_strlwr(temp);
00712 
00713     dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab);
00714     if (p)
00715     {
00716         // Entry found in the hashtable.  If a player, succeed if the
00717         // numbers match (already correctly in the hash table), fail
00718         // if they don't.
00719         //
00720         if (Good_obj(*p) && isPlayer(*p))
00721         {
00722             free_lbuf(temp);
00723             if (*p == player)
00724             {
00725                 return true;
00726             }
00727             else
00728             {
00729                 return false;
00730             }
00731         }
00732 
00733         // It's an alias (or an incorrect entry). Clobber it.
00734         //
00735         MEMFREE(p);
00736         p = (dbref *)MEMALLOC(sizeof(int));
00737         ISOUTOFMEMORY(p);
00738 
00739         *p = player;
00740         stat = hashreplLEN(temp, strlen(temp), p, &mudstate.player_htab);
00741         free_lbuf(temp);
00742     }
00743     else
00744     {
00745         p = (dbref *)MEMALLOC(sizeof(int));
00746         ISOUTOFMEMORY(p);
00747 
00748         *p = player;
00749         stat = (hashaddLEN(temp, strlen(temp), p, &mudstate.player_htab) >= 0);
00750         free_lbuf(temp);
00751     }
00752     return stat;
00753 }
00754 
00755 bool delete_player_name(dbref player, const char *name)
00756 {
00757     char *temp, *tp;
00758 
00759     tp = temp = alloc_lbuf("delete_player_name");
00760     safe_str(name, temp, &tp);
00761     *tp = '\0';
00762     mux_strlwr(temp);
00763 
00764     dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab);
00765     if (  !p
00766        || *p == NOTHING
00767        || (  player != NOTHING
00768           && *p != player))
00769     {
00770         free_lbuf(temp);
00771         return false;
00772     }
00773     MEMFREE(p);
00774     p = NULL;
00775     hashdeleteLEN(temp, strlen(temp), &mudstate.player_htab);
00776     free_lbuf(temp);
00777     return true;
00778 }
00779 
00780 dbref lookup_player(dbref doer, char *name, bool check_who)
00781 {
00782     if (string_compare(name, "me") == 0)
00783     {
00784         return doer;
00785     }
00786 
00787     while (*name == LOOKUP_TOKEN)
00788     {
00789         name++;
00790     }
00791     dbref thing;
00792     if (*name == NUMBER_TOKEN)
00793     {
00794         name++;
00795         if (!is_integer(name, NULL))
00796         {
00797             return NOTHING;
00798         }
00799         thing = mux_atol(name);
00800         if (!Good_obj(thing))
00801         {
00802             return NOTHING;
00803         }
00804         if ( !(  isPlayer(thing)
00805               || God(doer)))
00806         {
00807             thing = NOTHING;
00808         }
00809         return thing;
00810     }
00811     char *temp, *tp;
00812     tp = temp = alloc_lbuf("lookup_player");
00813     safe_str(name, temp, &tp);
00814     *tp = '\0';
00815     mux_strlwr(temp);
00816     dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab);
00817     free_lbuf(temp);
00818     if (!p)
00819     {
00820         if (check_who)
00821         {
00822             thing = find_connected_name(doer, name);
00823             if (Hidden(thing))
00824             {
00825                 thing = NOTHING;
00826             }
00827         }
00828         else
00829         {
00830             thing = NOTHING;
00831         }
00832     }
00833     else if (!Good_obj(*p))
00834     {
00835         thing = NOTHING;
00836     }
00837     else
00838     {
00839         thing = *p;
00840     }
00841 
00842     return thing;
00843 }
00844 
00845 void load_player_names(void)
00846 {
00847     dbref i;
00848     DO_WHOLE_DB(i)
00849     {
00850         if (isPlayer(i))
00851         {
00852             add_player_name(i, Name(i));
00853         }
00854     }
00855     char *alias = alloc_lbuf("load_player_names");
00856     DO_WHOLE_DB(i)
00857     {
00858         if (isPlayer(i))
00859         {
00860             dbref aowner;
00861             int aflags;
00862             alias = atr_pget_str(alias, i, A_ALIAS, &aowner, &aflags);
00863             if (*alias)
00864             {
00865                 add_player_name(i, alias);
00866             }
00867         }
00868     }
00869     free_lbuf(alias);
00870 }
00871 
00872 /* ---------------------------------------------------------------------------
00873  * badname_add, badname_check, badname_list: Add/look for/display bad names.
00874  */
00875 
00876 void badname_add(char *bad_name)
00877 {
00878     // Make a new node and link it in at the top.
00879     //
00880     BADNAME *bp = (BADNAME *)MEMALLOC(sizeof(BADNAME));
00881     ISOUTOFMEMORY(bp);
00882     bp->name = StringClone(bad_name);
00883     bp->next = mudstate.badname_head;
00884     mudstate.badname_head = bp;
00885 }
00886 
00887 void badname_remove(char *bad_name)
00888 {
00889     // Look for an exact match on the bad name and remove if found.
00890     //
00891     BADNAME *bp;
00892     BADNAME *backp = NULL;
00893     for (bp = mudstate.badname_head; bp; backp = bp, bp = bp->next)
00894     {
00895         if (!string_compare(bad_name, bp->name))
00896         {
00897             if (backp)
00898             {
00899                 backp->next = bp->next;
00900             }
00901             else
00902             {
00903                 mudstate.badname_head = bp->next;
00904             }
00905             MEMFREE(bp->name);
00906             bp->name = NULL;
00907             MEMFREE(bp);
00908             bp = NULL;
00909             return;
00910         }
00911     }
00912 }
00913 
00914 bool badname_check(char *bad_name)
00915 {
00916     BADNAME *bp;
00917 
00918     // Walk the badname list, doing wildcard matching.  If we get a hit then
00919     // return false.  If no matches in the list, return true.
00920     //
00921     for (bp = mudstate.badname_head; bp; bp = bp->next)
00922     {
00923         mudstate.wild_invk_ctr = 0;
00924         if (quick_wild(bp->name, bad_name))
00925         {
00926             return false;
00927         }
00928     }
00929     return true;
00930 }
00931 
00932 void badname_list(dbref player, const char *prefix)
00933 {
00934     BADNAME *bp;
00935     char *buff, *bufp;
00936 
00937     // Construct an lbuf with all the names separated by spaces.
00938     //
00939     buff = bufp = alloc_lbuf("badname_list");
00940     safe_str(prefix, buff, &bufp);
00941     for (bp = mudstate.badname_head; bp; bp = bp->next)
00942     {
00943         safe_chr(' ', buff, &bufp);
00944         safe_str(bp->name, buff, &bufp);
00945     }
00946     *bufp = '\0';
00947 
00948     // Now display it.
00949     //
00950     notify(player, buff);
00951     free_lbuf(buff);
00952 }

Generated on Mon May 28 04:40:11 2007 for MUX by  doxygen 1.4.7