mux/src/netcommon.cpp

Go to the documentation of this file.
00001 // netcommon.cpp
00002 //
00003 // $Id: netcommon.cpp,v 1.62 2006/01/07 18:17:49 sdennis Exp $
00004 //
00005 // This file contains routines used by the networking code that do not
00006 // depend on the implementation of the networking code.  The network-specific
00007 // portions of the descriptor data structure are not used.
00008 //
00009 
00010 #include "copyright.h"
00011 #include "autoconf.h"
00012 #include "config.h"
00013 #include "externs.h"
00014 
00015 #include <time.h>
00016 
00017 #include "ansi.h"
00018 #include "attrs.h"
00019 #include "command.h"
00020 #include "comsys.h"
00021 #include "file_c.h"
00022 #include "functions.h"
00023 #include "mguests.h"
00024 #include "powers.h"
00025 #include "svdreport.h"
00026 #ifdef REALITY_LVLS
00027 #include "levels.h"
00028 #endif /* REALITY_LVLS */
00029 
00030 
00031 /* ---------------------------------------------------------------------------
00032  * make_portlist: Make a list of ports for PORTS().
00033  */
00034 
00035 void make_portlist(dbref player, dbref target, char *buff, char **bufc)
00036 {
00037     UNUSED_PARAMETER(player);
00038 
00039     ITL itl;
00040     ItemToList_Init(&itl, buff, bufc);
00041 
00042     DESC *d;
00043     DESC_ITER_CONN(d)
00044     {
00045         if (  d->player == target
00046            && !ItemToList_AddInteger(&itl, d->descriptor))
00047         {
00048             break;
00049         }
00050     }
00051     ItemToList_Final(&itl);
00052 }
00053 
00054 // ---------------------------------------------------------------------------
00055 // make_port_ulist: Make a list of connected user numbers for the LPORTS function.
00056 // ---------------------------------------------------------------------------
00057 
00058 void make_port_ulist(dbref player, char *buff, char **bufc)
00059 {
00060     DESC *d;
00061     ITL itl;
00062     char *tmp = alloc_sbuf("make_port_ulist");
00063     ItemToList_Init(&itl, buff, bufc, '#');
00064     DESC_ITER_CONN(d)
00065     {
00066         if (  !See_Hidden(player)
00067            && Hidden(d->player))
00068         {
00069             continue;
00070         }
00071 
00072         // printf format: printf("%d:%d", d->player, d->descriptor);
00073         //
00074         char *p = tmp;
00075         p += mux_ltoa(d->player, p);
00076         *p++ = ':';
00077         p += mux_ltoa(d->descriptor, p);
00078 
00079         size_t n = p - tmp;
00080         if (!ItemToList_AddStringLEN(&itl, n, tmp))
00081         {
00082             break;
00083         }
00084     }
00085     ItemToList_Final(&itl);
00086     free_sbuf(tmp);
00087 }
00088 
00089 /* ---------------------------------------------------------------------------
00090  * update_quotas: Update timeslice quotas
00091  */
00092 
00093 void update_quotas(CLinearTimeAbsolute& ltaLast, const CLinearTimeAbsolute& ltaCurrent)
00094 {
00095     if (ltaCurrent < ltaLast)
00096     {
00097         ltaLast = ltaCurrent;
00098         return;
00099     }
00100 
00101     CLinearTimeDelta ltdDiff = ltaCurrent - ltaLast;
00102     if (ltdDiff < mudconf.timeslice)
00103     {
00104         return;
00105     }
00106 
00107     int nSlices = ltdDiff / mudconf.timeslice;
00108     int nExtraQuota = mudconf.cmd_quota_incr * nSlices;
00109 
00110     if (nExtraQuota > 0)
00111     {
00112         DESC *d;
00113         DESC_ITER_ALL(d)
00114         {
00115             d->quota += nExtraQuota;
00116             if (d->quota > mudconf.cmd_quota_max)
00117             {
00118                 d->quota = mudconf.cmd_quota_max;
00119             }
00120         }
00121     }
00122     ltaLast += mudconf.timeslice * nSlices;
00123 }
00124 
00125 /* raw_notify_html() -- raw_notify() without the newline */
00126 void raw_notify_html(dbref player, const char *msg)
00127 {
00128     if (!msg || !*msg)
00129     {
00130         return;
00131     }
00132 
00133     if (  mudstate.inpipe
00134        && player == mudstate.poutobj)
00135     {
00136         safe_str(msg, mudstate.poutnew, &mudstate.poutbufc);
00137         return;
00138     }
00139     if (  !Connected(player)
00140        || !Html(player))
00141     {
00142         return;
00143     }
00144 
00145     DESC *d;
00146     DESC_ITER_PLAYER(player, d)
00147     {
00148         queue_string(d, msg);
00149     }
00150 }
00151 
00152 /* ---------------------------------------------------------------------------
00153  * raw_notify: write a message to a player
00154  */
00155 
00156 void raw_notify(dbref player, const char *msg)
00157 {
00158     DESC *d;
00159 
00160     if (!msg || !*msg)
00161     {
00162         return;
00163     }
00164 
00165     if (  mudstate.inpipe
00166        && player == mudstate.poutobj)
00167     {
00168         safe_str(msg, mudstate.poutnew, &mudstate.poutbufc);
00169         safe_str("\r\n", mudstate.poutnew, &mudstate.poutbufc);
00170         return;
00171     }
00172 
00173     if (!Connected(player))
00174     {
00175         return;
00176     }
00177 
00178     DESC_ITER_PLAYER(player, d)
00179     {
00180         queue_string(d, msg);
00181         queue_write_LEN(d, "\r\n", 2);
00182     }
00183 }
00184 
00185 void raw_notify_newline(dbref player)
00186 {
00187     if (  mudstate.inpipe
00188        && player == mudstate.poutobj)
00189     {
00190         safe_str("\r\n", mudstate.poutnew, &mudstate.poutbufc);
00191         return;
00192     }
00193     if (!Connected(player))
00194     {
00195         return;
00196     }
00197 
00198     DESC *d;
00199     DESC_ITER_PLAYER(player, d)
00200     {
00201         queue_write_LEN(d, "\r\n", 2);
00202     }
00203 }
00204 
00205 /* ---------------------------------------------------------------------------
00206  * raw_broadcast: Send message to players who have indicated flags
00207  */
00208 
00209 void DCL_CDECL raw_broadcast(int inflags, char *fmt, ...)
00210 {
00211     if (!fmt || !*fmt)
00212     {
00213         return;
00214     }
00215 
00216     char buff[LBUF_SIZE];
00217 
00218     va_list ap;
00219     va_start(ap, fmt);
00220     mux_vsnprintf(buff, LBUF_SIZE, fmt, ap);
00221     va_end(ap);
00222 
00223     DESC *d;
00224     DESC_ITER_CONN(d)
00225     {
00226         if ((Flags(d->player) & inflags) == inflags)
00227         {
00228             queue_string(d, buff);
00229             queue_write_LEN(d, "\r\n", 2);
00230             process_output(d, false);
00231         }
00232     }
00233 }
00234 
00235 /* ---------------------------------------------------------------------------
00236  * clearstrings: clear out prefix and suffix strings
00237  */
00238 
00239 void clearstrings(DESC *d)
00240 {
00241     if (d->output_prefix)
00242     {
00243         free_lbuf(d->output_prefix);
00244         d->output_prefix = NULL;
00245     }
00246     if (d->output_suffix)
00247     {
00248         free_lbuf(d->output_suffix);
00249         d->output_suffix = NULL;
00250     }
00251 }
00252 
00253 static void add_to_output_queue(DESC *d, const char *b, int n)
00254 {
00255     TBLOCK *tp;
00256     int left;
00257 
00258     // Allocate an output buffer if needed.
00259     //
00260     if (d->output_head == NULL)
00261     {
00262         tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE);
00263         ISOUTOFMEMORY(tp);
00264         tp->hdr.nxt = NULL;
00265         tp->hdr.start = tp->data;
00266         tp->hdr.end = tp->data;
00267         tp->hdr.nchars = 0;
00268         d->output_head = tp;
00269         d->output_tail = tp;
00270     }
00271     else
00272     {
00273         tp = d->output_tail;
00274     }
00275 
00276     // Now tp points to the last buffer in the chain.
00277     //
00278     do
00279     {
00280         // See if there is enough space in the buffer to hold the
00281         // string.  If so, copy it and update the pointers..
00282         //
00283         left = OUTPUT_BLOCK_SIZE - (tp->hdr.end - (char *)tp + 1);
00284         if (n <= left)
00285         {
00286             memcpy(tp->hdr.end, b, n);
00287             tp->hdr.end += n;
00288             tp->hdr.nchars += n;
00289             n = 0;
00290         }
00291         else
00292         {
00293             // It didn't fit.  Copy what will fit and then allocate
00294             // another buffer and retry.
00295             //
00296             if (left > 0)
00297             {
00298                 memcpy(tp->hdr.end, b, left);
00299                 tp->hdr.end += left;
00300                 tp->hdr.nchars += left;
00301                 b += left;
00302                 n -= left;
00303             }
00304             tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE);
00305             ISOUTOFMEMORY(tp);
00306             tp->hdr.nxt = NULL;
00307             tp->hdr.start = tp->data;
00308             tp->hdr.end = tp->data;
00309             tp->hdr.nchars = 0;
00310             d->output_tail->hdr.nxt = tp;
00311             d->output_tail = tp;
00312         }
00313     } while (n > 0);
00314 }
00315 
00316 /* ---------------------------------------------------------------------------
00317  * queue_write: Add text to the output queue for the indicated descriptor.
00318  */
00319 
00320 void queue_write_LEN(DESC *d, const char *b, int n)
00321 {
00322     if (n <= 0)
00323     {
00324         return;
00325     }
00326 
00327     if (d->output_size + n > mudconf.output_limit)
00328     {
00329         process_output(d, false);
00330     }
00331 
00332     int left = mudconf.output_limit - d->output_size - n;
00333     if (left < 0)
00334     {
00335         TBLOCK *tp = d->output_head;
00336         if (tp == NULL)
00337         {
00338             STARTLOG(LOG_PROBLEMS, "QUE", "WRITE");
00339             log_text("Flushing when output_head is null!");
00340             ENDLOG;
00341         }
00342         else
00343         {
00344             STARTLOG(LOG_NET, "NET", "WRITE");
00345             char *buf = alloc_lbuf("queue_write.LOG");
00346             sprintf(buf, "[%u/%s] Output buffer overflow, %d chars discarded by ", d->descriptor, d->addr, tp->hdr.nchars);
00347             log_text(buf);
00348             free_lbuf(buf);
00349             if (d->flags & DS_CONNECTED)
00350             {
00351                 log_name(d->player);
00352             }
00353             ENDLOG;
00354             d->output_size -= tp->hdr.nchars;
00355             d->output_head = tp->hdr.nxt;
00356             d->output_lost += tp->hdr.nchars;
00357             if (d->output_head == NULL)
00358             {
00359                 d->output_tail = NULL;
00360             }
00361             MEMFREE(tp);
00362             tp = NULL;
00363         }
00364     }
00365 
00366     add_to_output_queue(d, b, n);
00367     d->output_size += n;
00368     d->output_tot += n;
00369 
00370 #ifdef WIN32
00371     if (  platform == VER_PLATFORM_WIN32_NT
00372        && !d->bWritePending
00373        && !d->bConnectionDropped)
00374     {
00375         d->bCallProcessOutputLater = true;
00376     }
00377 #endif
00378 }
00379 
00380 void queue_write(DESC *d, const char *b)
00381 {
00382     queue_write_LEN(d, b, strlen(b));
00383 }
00384 
00385 static const char *encode_iac(const char *szString)
00386 {
00387     static char Buffer[2*LBUF_SIZE];
00388     char *pBuffer = Buffer;
00389 
00390     const char *pString = szString;
00391     if (pString)
00392     {
00393         while (*pString)
00394         {
00395             const char *p = strchr(pString, NVT_IAC);
00396             if (!p)
00397             {
00398                 // NVT_IAC does not appear in the buffer. This is by far the most-common case.
00399                 //
00400                 if (pString == szString)
00401                 {
00402                     // Avoid copying to the static buffer, and just return the original buffer.
00403                     //
00404                     return szString;
00405                 }
00406                 else
00407                 {
00408                     strcpy(pBuffer, pString);
00409                     return Buffer;
00410                 }
00411             }
00412             else
00413             {
00414                 // Copy up to and including the IAC.
00415                 //
00416                 size_t n = p - pString + 1;
00417                 memcpy(pBuffer, pString, n);
00418                 pBuffer += n;
00419                 pString += n;
00420 
00421                 // Add another IAC.
00422                 //
00423                 *pBuffer++ = NVT_IAC;
00424             }
00425         }
00426     }
00427     *pBuffer = '\0';
00428     return Buffer;
00429 }
00430 
00431 void queue_string(DESC *d, const char *s)
00432 {
00433     const char *p = s;
00434 
00435     if (d->flags & DS_CONNECTED)
00436     {
00437         if (  !Ansi(d->player)
00438            && strchr(s, ESC_CHAR))
00439         {
00440             p = strip_ansi(p);
00441         }
00442         else if (NoBleed(d->player))
00443         {
00444             p = normal_to_white(p);
00445         }
00446 
00447         if (NoAccents(d->player))
00448         {
00449             p = strip_accents(p);
00450         }
00451     }
00452     else
00453     {
00454         if (strchr(s, ESC_CHAR))
00455         {
00456             p = strip_ansi(p);
00457         }
00458         p = strip_accents(p);
00459     }
00460     p = encode_iac(p);
00461     queue_write(d, p);
00462 }
00463 
00464 void freeqs(DESC *d)
00465 {
00466     TBLOCK *tb, *tnext;
00467     CBLK *cb, *cnext;
00468 
00469     tb = d->output_head;
00470     while (tb)
00471     {
00472         tnext = tb->hdr.nxt;
00473         MEMFREE(tb);
00474         tb = tnext;
00475     }
00476     d->output_head = NULL;
00477     d->output_tail = NULL;
00478 
00479     cb = d->input_head;
00480     while (cb)
00481     {
00482         cnext = (CBLK *) cb->hdr.nxt;
00483         free_lbuf(cb);
00484         cb = cnext;
00485     }
00486 
00487     d->input_head = NULL;
00488     d->input_tail = NULL;
00489 
00490     if (d->raw_input)
00491     {
00492         free_lbuf(d->raw_input);
00493     }
00494     d->raw_input = NULL;
00495 
00496     d->raw_input_at = NULL;
00497     d->nOption = 0;
00498     d->raw_input_state    = NVT_IS_NORMAL;
00499     d->nvt_sga_him_state  = OPTION_NO;
00500     d->nvt_sga_us_state   = OPTION_NO;
00501     d->nvt_eor_him_state  = OPTION_NO;
00502     d->nvt_eor_us_state   = OPTION_NO;
00503     d->nvt_naws_him_state = OPTION_NO;
00504     d->nvt_naws_us_state  = OPTION_NO;
00505     d->height = 24;
00506     d->width = 78;
00507 }
00508 
00509 /* ---------------------------------------------------------------------------
00510  * desc_addhash: Add a net descriptor to its player hash list.
00511  */
00512 
00513 void desc_addhash(DESC *d)
00514 {
00515     dbref player = d->player;
00516     DESC *hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab);
00517     if (hdesc == NULL)
00518     {
00519         d->hashnext = NULL;
00520         hashaddLEN(&player, sizeof(player), d, &mudstate.desc_htab);
00521     }
00522     else
00523     {
00524         d->hashnext = hdesc;
00525         hashreplLEN(&player, sizeof(player), d, &mudstate.desc_htab);
00526     }
00527 }
00528 
00529 /* ---------------------------------------------------------------------------
00530  * desc_delhash: Remove a net descriptor from its player hash list.
00531  */
00532 
00533 static void desc_delhash(DESC *d)
00534 {
00535     dbref player = d->player;
00536     DESC *last = NULL;
00537     DESC *hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab);
00538     while (hdesc != NULL)
00539     {
00540         if (d == hdesc)
00541         {
00542             if (last == NULL)
00543             {
00544                 if (d->hashnext == NULL)
00545                 {
00546                     hashdeleteLEN(&player, sizeof(player), &mudstate.desc_htab);
00547                 }
00548                 else
00549                 {
00550                     hashreplLEN(&player, sizeof(player), d->hashnext, &mudstate.desc_htab);
00551                 }
00552             }
00553             else
00554             {
00555                 last->hashnext = d->hashnext;
00556             }
00557             break;
00558         }
00559         last = hdesc;
00560         hdesc = hdesc->hashnext;
00561     }
00562     d->hashnext = NULL;
00563 }
00564 
00565 void welcome_user(DESC *d)
00566 {
00567     if (d->host_info & H_REGISTRATION)
00568     {
00569         fcache_dump(d, FC_CONN_REG);
00570     }
00571     else
00572     {
00573         fcache_dump(d, FC_CONN);
00574     }
00575 }
00576 
00577 void save_command(DESC *d, CBLK *command)
00578 {
00579     command->hdr.nxt = NULL;
00580     if (d->input_tail == NULL)
00581     {
00582         d->input_head = command;
00583 
00584         // We have added our first command to an empty list. Go process it later.
00585         //
00586         scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_ProcessCommand, d, 0);
00587     }
00588     else
00589     {
00590         d->input_tail->hdr.nxt = command;
00591     }
00592     d->input_tail = command;
00593 }
00594 
00595 static void set_userstring(char **userstring, const char *command)
00596 {
00597     while (mux_isspace(*command))
00598     {
00599         command++;
00600     }
00601 
00602     if (!*command)
00603     {
00604         if (*userstring != NULL)
00605         {
00606             free_lbuf(*userstring);
00607             *userstring = NULL;
00608         }
00609     }
00610     else
00611     {
00612         if (*userstring == NULL)
00613         {
00614             *userstring = alloc_lbuf("set_userstring");
00615         }
00616         strcpy(*userstring, command);
00617     }
00618 }
00619 
00620 static void parse_connect(const char *msg, char *command, char *user, char *pass)
00621 {
00622     if (strlen(msg) > MBUF_SIZE)
00623     {
00624         *command = '\0';
00625         *user = '\0';
00626         *pass = '\0';
00627         return;
00628     }
00629     while (mux_isspace(*msg))
00630     {
00631         msg++;
00632     }
00633     char *p = command;
00634     while (  *msg
00635           && !mux_isspace(*msg))
00636     {
00637         *p++ = *msg++;
00638     }
00639     *p = '\0';
00640     while (mux_isspace(*msg))
00641     {
00642         msg++;
00643     }
00644     p = user;
00645     if (  mudconf.name_spaces
00646        && *msg == '\"')
00647     {
00648         for (; *msg && (*msg == '\"' || mux_isspace(*msg)); msg++)
00649         {
00650             // Nothing.
00651         }
00652         while (  *msg
00653               && *msg != '\"')
00654         {
00655             while (  *msg
00656                   && !mux_isspace(*msg)
00657                   && *msg != '\"')
00658             {
00659                 *p++ = *msg++;
00660             }
00661 
00662             if (*msg == '\"')
00663             {
00664                 break;
00665             }
00666 
00667             while (mux_isspace(*msg))
00668             {
00669                 msg++;
00670             }
00671 
00672             if (  *msg
00673                && *msg != '\"')
00674             {
00675                 *p++ = ' ';
00676             }
00677         }
00678         while (  *msg
00679               && *msg == '\"')
00680         {
00681              msg++;
00682         }
00683     }
00684     else
00685     {
00686         while (  *msg
00687               && !mux_isspace(*msg))
00688         {
00689             *p++ = *msg++;
00690         }
00691     }
00692     *p = '\0';
00693     while (mux_isspace(*msg))
00694     {
00695         msg++;
00696     }
00697     p = pass;
00698     while (  *msg
00699           && !mux_isspace(*msg))
00700     {
00701         *p++ = *msg++;
00702     }
00703     *p = '\0';
00704 }
00705 
00706 static void announce_connect(dbref player, DESC *d)
00707 {
00708     desc_addhash(d);
00709 
00710     DESC *dtemp;
00711     int count = 0;
00712     DESC_ITER_CONN(dtemp)
00713     {
00714         count++;
00715     }
00716 
00717     if (mudstate.record_players < count)
00718     {
00719         mudstate.record_players = count;
00720     }
00721 
00722     char *buf = alloc_lbuf("announce_connect");
00723     dbref aowner;
00724     int aflags;
00725     size_t nLen;
00726     atr_pget_str_LEN(buf, player, A_TIMEOUT, &aowner, &aflags, &nLen);
00727     if (nLen)
00728     {
00729         d->timeout = mux_atol(buf);
00730         if (d->timeout <= 0)
00731         {
00732             d->timeout = mudconf.idle_timeout;
00733         }
00734     }
00735 
00736     dbref loc = Location(player);
00737     s_Connected(player);
00738 
00739     if (d->flags & DS_PUEBLOCLIENT)
00740     {
00741         s_Html(player);
00742     }
00743 
00744     raw_notify( player, tprintf("\n%sMOTD:%s %s\n", ANSI_HILITE,
00745                 ANSI_NORMAL, mudconf.motd_msg));
00746 
00747     if (Wizard(player))
00748     {
00749         raw_notify(player, tprintf("%sWIZMOTD:%s %s\n", ANSI_HILITE,
00750             ANSI_NORMAL, mudconf.wizmotd_msg));
00751 
00752         if (!(mudconf.control_flags & CF_LOGIN))
00753         {
00754             raw_notify(player, "*** Logins are disabled.");
00755         }
00756     }
00757     atr_get_str_LEN(buf, player, A_LPAGE, &aowner, &aflags, &nLen);
00758     if (nLen)
00759     {
00760         raw_notify(player, "Your PAGE LOCK is set.  You may be unable to receive some pages.");
00761     }
00762     int num = 0;
00763     DESC_ITER_PLAYER(player, dtemp)
00764     {
00765         num++;
00766     }
00767 
00768     // Reset vacation flag.
00769     //
00770     s_Flags(player, FLAG_WORD2, Flags2(player) & ~VACATION);
00771 
00772     char *pRoomAnnounceFmt;
00773     char *pMonitorAnnounceFmt;
00774     if (num < 2)
00775     {
00776         pRoomAnnounceFmt = "%s has connected.";
00777         if (mudconf.have_comsys)
00778         {
00779             do_comconnect(player);
00780         }
00781         if (  Hidden(player)
00782            && Can_Hide(player))
00783         {
00784             pMonitorAnnounceFmt = "GAME: %s has DARK-connected.";
00785         }
00786         else
00787         {
00788             pMonitorAnnounceFmt = "GAME: %s has connected.";
00789         }
00790         if (  Suspect(player)
00791            || (d->host_info & H_SUSPECT))
00792         {
00793             raw_broadcast(WIZARD, "[Suspect] %s has connected.", Moniker(player));
00794         }
00795     }
00796     else
00797     {
00798         pRoomAnnounceFmt = "%s has reconnected.";
00799         pMonitorAnnounceFmt = "GAME: %s has reconnected.";
00800         if (  Suspect(player)
00801            || (d->host_info & H_SUSPECT))
00802         {
00803             raw_broadcast(WIZARD, "[Suspect] %s has reconnected.", Moniker(player));
00804         }
00805     }
00806     sprintf(buf, pRoomAnnounceFmt, Moniker(player));
00807     raw_broadcast(MONITOR, pMonitorAnnounceFmt, Moniker(player));
00808 
00809     int key = MSG_INV;
00810     if (  loc != NOTHING
00811        && !(  Hidden(player)
00812            && Can_Hide(player)))
00813     {
00814         key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST);
00815     }
00816 
00817     dbref temp = mudstate.curr_enactor;
00818     mudstate.curr_enactor = player;
00819 #ifdef REALITY_LVLS
00820     if(loc == NOTHING)
00821         notify_check(player, player, buf, key);
00822     else
00823         notify_except_rlevel(loc, player, player, buf, 0);
00824 #else
00825     notify_check(player, player, buf, key);
00826 #endif /* REALITY_LVLS */
00827     atr_pget_str_LEN(buf, player, A_ACONNECT, &aowner, &aflags, &nLen);
00828     CLinearTimeAbsolute lta;
00829     dbref zone, obj;
00830     if (nLen)
00831     {
00832         wait_que(player, player, player, false, lta, NOTHING, 0, buf,
00833             (char **)NULL, 0, NULL);
00834     }
00835     if (mudconf.master_room != NOTHING)
00836     {
00837         atr_pget_str_LEN(buf, mudconf.master_room, A_ACONNECT, &aowner,
00838             &aflags, &nLen);
00839         if (nLen)
00840         {
00841             wait_que(mudconf.master_room, player, player, false, lta,
00842                 NOTHING, 0, buf, (char **)NULL, 0, NULL);
00843         }
00844         DOLIST(obj, Contents(mudconf.master_room))
00845         {
00846             atr_pget_str_LEN(buf, obj, A_ACONNECT, &aowner, &aflags, &nLen);
00847             if (nLen)
00848             {
00849                 wait_que(obj, player, player, false, lta, NOTHING, 0, buf,
00850                     (char **)NULL, 0, NULL);
00851             }
00852         }
00853     }
00854 
00855     // Do the zone of the player's location's possible aconnect.
00856     //
00857     if (  mudconf.have_zones
00858        && Good_obj(zone = Zone(loc)))
00859     {
00860         switch (Typeof(zone))
00861         {
00862         case TYPE_THING:
00863 
00864             atr_pget_str_LEN(buf, zone, A_ACONNECT, &aowner, &aflags, &nLen);
00865             if (nLen)
00866             {
00867                 wait_que(zone, player, player, false, lta, NOTHING, 0, buf,
00868                     (char **)NULL, 0, NULL);
00869             }
00870             break;
00871 
00872         case TYPE_ROOM:
00873 
00874             // check every object in the room for a connect action.
00875             //
00876             DOLIST(obj, Contents(zone))
00877             {
00878                 atr_pget_str_LEN(buf, obj, A_ACONNECT, &aowner, &aflags,
00879                     &nLen);
00880                 if (nLen)
00881                 {
00882                     wait_que(obj, player, player, false, lta, NOTHING, 0,
00883                         buf, (char **)NULL, 0, NULL);
00884                 }
00885             }
00886             break;
00887 
00888         default:
00889 
00890             log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d",
00891                 zone, Name(player), player, Typeof(zone)));
00892         }
00893     }
00894     free_lbuf(buf);
00895     CLinearTimeAbsolute ltaNow;
00896     ltaNow.GetLocal();
00897     char *time_str = ltaNow.ReturnDateString(7);
00898 
00899     record_login(player, true, time_str, d->addr, d->username,
00900         inet_ntoa((d->address).sin_addr));
00901     if (mudconf.have_mailer)
00902     {
00903         check_mail(player, 0, false);
00904     }
00905     look_in(player, Location(player), (LK_SHOWEXIT|LK_OBEYTERSE|LK_SHOWVRML));
00906     mudstate.curr_enactor = temp;
00907     if (Guest(player))
00908     {
00909         db[player].fs.word[FLAG_WORD1] &= ~DARK;
00910     }
00911 }
00912 
00913 void announce_disconnect(dbref player, DESC *d, const char *reason)
00914 {
00915     int num = 0, key;
00916     DESC *dtemp;
00917     DESC_ITER_PLAYER(player, dtemp)
00918     {
00919         num++;
00920     }
00921 
00922     dbref temp = mudstate.curr_enactor;
00923     mudstate.curr_enactor = player;
00924     dbref loc = Location(player);
00925 
00926     if (num < 2)
00927     {
00928         if (  Suspect(player)
00929            || (d->host_info & H_SUSPECT))
00930         {
00931             raw_broadcast(WIZARD, "[Suspect] %s has disconnected.", Moniker(player));
00932         }
00933         char *buf = alloc_lbuf("announce_disconnect.only");
00934 
00935         sprintf(buf, "%s has disconnected.", Moniker(player));
00936         key = MSG_INV;
00937         if (  loc != NOTHING
00938            && !(  Hidden(player)
00939                && Can_Hide(player)))
00940         {
00941             key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST);
00942         }
00943 #ifdef REALITY_LVLS
00944         if(loc == NOTHING)
00945             notify_check(player, player, buf, key);
00946         else
00947             notify_except_rlevel(loc, player, player, buf, 0);
00948 #else
00949         notify_check(player, player, buf, key);
00950 #endif /* REALITY_LVLS */
00951 
00952         if (mudconf.have_mailer)
00953         {
00954             do_mail_purge(player);
00955         }
00956 
00957         raw_broadcast(MONITOR, "GAME: %s has disconnected. <%s>", Moniker(player), reason);
00958 
00959         c_Connected(player);
00960 
00961         if (mudconf.have_comsys)
00962         {
00963             do_comdisconnect(player);
00964         }
00965 
00966         dbref aowner, zone, obj;
00967         int aflags;
00968         size_t nLen;
00969         char *argv[1];
00970         argv[0] = (char *)reason;
00971         CLinearTimeAbsolute lta;
00972         atr_pget_str_LEN(buf, player, A_ADISCONNECT, &aowner, &aflags, &nLen);
00973         if (nLen)
00974         {
00975             wait_que(player, player, player, false, lta, NOTHING, 0, buf,
00976                 argv, 1, NULL);
00977         }
00978         if (mudconf.master_room != NOTHING)
00979         {
00980             atr_pget_str_LEN(buf, mudconf.master_room, A_ADISCONNECT, &aowner,
00981                 &aflags, &nLen);
00982             if (nLen)
00983             {
00984                 wait_que(mudconf.master_room, player, player, false, lta,
00985                     NOTHING, 0, buf, (char **)NULL, 0, NULL);
00986             }
00987             DOLIST(obj, Contents(mudconf.master_room))
00988             {
00989                 atr_pget_str_LEN(buf, obj, A_ADISCONNECT, &aowner, &aflags,
00990                     &nLen);
00991                 if (nLen)
00992                 {
00993                     wait_que(obj, player, player, false, lta, NOTHING, 0,
00994                         buf, (char **)NULL, 0, NULL);
00995                 }
00996             }
00997         }
00998 
00999         // Do the zone of the player's location's possible adisconnect.
01000         //
01001         if (mudconf.have_zones && Good_obj(zone = Zone(loc)))
01002         {
01003             switch (Typeof(zone))
01004             {
01005             case TYPE_THING:
01006 
01007                 atr_pget_str_LEN(buf, zone, A_ADISCONNECT, &aowner, &aflags,
01008                     &nLen);
01009                 if (nLen)
01010                 {
01011                     wait_que(zone, player, player, false, lta, NOTHING, 0,
01012                         buf, (char **)NULL, 0, NULL);
01013                 }
01014                 break;
01015 
01016             case TYPE_ROOM:
01017 
01018                 // check every object in the room for a connect action.
01019                 //
01020                 DOLIST(obj, Contents(zone))
01021                 {
01022                     atr_pget_str_LEN(buf, obj, A_ADISCONNECT, &aowner, &aflags,
01023                         &nLen);
01024                     if (nLen)
01025                     {
01026                         wait_que(obj, player, player, false, lta, NOTHING,
01027                             0, buf, (char **)NULL, 0, NULL);
01028                     }
01029                 }
01030                 break;
01031 
01032             default:
01033                 log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d",
01034                     zone, Name(player), player, Typeof(zone)));
01035             }
01036         }
01037         free_lbuf(buf);
01038         if (d->flags & DS_AUTODARK)
01039         {
01040             d->flags &= ~DS_AUTODARK;
01041             db[player].fs.word[FLAG_WORD1] &= ~DARK;
01042         }
01043 
01044         if (Guest(player))
01045         {
01046             db[player].fs.word[FLAG_WORD1] |= DARK;
01047             halt_que(NOTHING, player);
01048         }
01049     }
01050     else
01051     {
01052         if (  Suspect(player)
01053            || (d->host_info & H_SUSPECT))
01054         {
01055             raw_broadcast(WIZARD, "[Suspect] %s has partially disconnected.", Moniker(player));
01056         }
01057         char *mbuf = alloc_mbuf("announce_disconnect.partial");
01058         sprintf(mbuf, "%s has partially disconnected.", Moniker(player));
01059         key = MSG_INV;
01060         if (  loc != NOTHING
01061            && !(  Hidden(player)
01062                && Can_Hide(player)))
01063         {
01064             key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST);
01065         }
01066 #ifdef REALITY_LVLS
01067         if(loc == NOTHING)
01068             notify_check(player, player, mbuf, key);
01069         else
01070             notify_except_rlevel(loc, player, player, mbuf, 0);
01071 #else
01072         notify_check(player, player, mbuf, key);
01073 #endif /* REALITY_LVLS */
01074         raw_broadcast(MONITOR, "GAME: %s has partially disconnected.",
01075             Moniker(player));
01076         free_mbuf(mbuf);
01077     }
01078 
01079     mudstate.curr_enactor = temp;
01080     desc_delhash(d);
01081 
01082     local_disconnect(player, num);
01083 }
01084 
01085 int boot_off(dbref player, const char *message)
01086 {
01087     DESC *d, *dnext;
01088     int count = 0;
01089     DESC_SAFEITER_PLAYER(player, d, dnext)
01090     {
01091         if (message && *message)
01092         {
01093             queue_string(d, message);
01094             queue_write_LEN(d, "\r\n", 2);
01095         }
01096         shutdownsock(d, R_BOOT);
01097         count++;
01098     }
01099     return count;
01100 }
01101 
01102 int boot_by_port(SOCKET port, bool bGod, const char *message)
01103 {
01104     DESC *d, *dnext;
01105     int count = 0;
01106     DESC_SAFEITER_ALL(d, dnext)
01107     {
01108         if (  d->descriptor == port
01109            && (  bGod
01110               || !(d->flags & DS_CONNECTED)
01111               || !God(d->player)))
01112         {
01113             if (  message
01114                && *message)
01115             {
01116                 queue_string(d, message);
01117                 queue_write_LEN(d, "\r\n", 2);
01118             }
01119             shutdownsock(d, R_BOOT);
01120             count++;
01121         }
01122     }
01123     return count;
01124 }
01125 
01126 /* ---------------------------------------------------------------------------
01127  * desc_reload: Reload parts of net descriptor that are based on db info.
01128  */
01129 
01130 void desc_reload(dbref player)
01131 {
01132