mux/src/comsys.cpp

Go to the documentation of this file.
00001 // comsys.cpp
00002 //
00003 // $Id: comsys.cpp,v 1.45 2007/03/17 04:25:08 sdennis Exp $
00004 //
00005 #include "copyright.h"
00006 #include "autoconf.h"
00007 #include "config.h"
00008 #include "externs.h"
00009 
00010 #include <sys/types.h>
00011 
00012 #include "ansi.h"
00013 #include "attrs.h"
00014 #include "command.h"
00015 #include "comsys.h"
00016 #include "functions.h"
00017 #include "interface.h"
00018 #include "powers.h"
00019 
00020 static int num_channels;
00021 static comsys_t *comsys_table[NUM_COMSYS];
00022 
00023 #define DFLT_MAX_LOG        0
00024 #define MIN_RECALL_REQUEST  1
00025 #define DFLT_RECALL_REQUEST 10
00026 #define MAX_RECALL_REQUEST  200
00027 
00028 // Return value must be free_lbuf'ed.
00029 //
00030 static char *RestrictTitleValue(char *pTitleRequest)
00031 {
00032     // First, remove all '\r\n\t' from the string.
00033     //
00034     char *pNewTitle = RemoveSetOfCharacters(pTitleRequest, "\r\n\t");
00035 
00036     // Optimize/terminate any ANSI in the string.
00037     //
00038     char NewTitle_ANSI[MAX_TITLE_LEN+1];
00039     int nVisualWidth;
00040     int nLen = ANSI_TruncateToField(pNewTitle, sizeof(NewTitle_ANSI),
00041         NewTitle_ANSI, sizeof(NewTitle_ANSI), &nVisualWidth,
00042         ANSI_ENDGOAL_NORMAL);
00043     memcpy(pNewTitle, NewTitle_ANSI, nLen+1);
00044     return pNewTitle;
00045 }
00046 
00047 static void do_setcomtitlestatus(dbref player, struct channel *ch, bool status)
00048 {
00049     struct comuser *user = select_user(ch,player);
00050     if (ch && user)
00051     {
00052         user->ComTitleStatus = status;
00053     }
00054 }
00055 
00056 static void do_setnewtitle(dbref player, struct channel *ch, char *pValidatedTitle)
00057 {
00058     struct comuser *user = select_user(ch, player);
00059 
00060     if (ch && user)
00061     {
00062         if (user->title)
00063         {
00064             MEMFREE(user->title);
00065             user->title = NULL;
00066         }
00067         user->title = StringClone(pValidatedTitle);
00068     }
00069 }
00070 
00071 void load_comsys(char *filename)
00072 {
00073     int i;
00074     char buffer[200];
00075 
00076     for (i = 0; i < NUM_COMSYS; i++)
00077     {
00078         comsys_table[i] = NULL;
00079     }
00080 
00081     FILE *fp = fopen(filename, "rb");
00082     if (!fp)
00083     {
00084         Log.tinyprintf("Error: Couldn't find %s." ENDLINE, filename);
00085     }
00086     else
00087     {
00088         DebugTotalFiles++;
00089         Log.tinyprintf("LOADING: %s" ENDLINE, filename);
00090         if (fscanf(fp, "*** Begin %s ***\n", buffer) == 1 && !strcmp(buffer, "CHANNELS"))
00091         {
00092             load_channels(fp);
00093         }
00094         else
00095         {
00096             Log.tinyprintf("Error: Couldn't find Begin CHANNELS in %s.", filename);
00097             if (fclose(fp) == 0)
00098             {
00099                 DebugTotalFiles--;
00100             }
00101             return;
00102         }
00103 
00104         if (fscanf(fp, "*** Begin %s ***\n", buffer) == 1 && !strcmp(buffer, "COMSYS"))
00105         {
00106             load_comsystem(fp);
00107         }
00108         else
00109         {
00110             Log.tinyprintf("Error: Couldn't find Begin COMSYS in %s.", filename);
00111             if (fclose(fp) == 0)
00112             {
00113                 DebugTotalFiles--;
00114             }
00115             return;
00116         }
00117 
00118         if (fclose(fp) == 0)
00119         {
00120             DebugTotalFiles--;
00121         }
00122         Log.tinyprintf("LOADING: %s (done)" ENDLINE, filename);
00123     }
00124 }
00125 
00126 void save_comsys(char *filename)
00127 {
00128     char buffer[500];
00129 
00130     sprintf(buffer, "%s.#", filename);
00131     FILE *fp = fopen(buffer, "wb");
00132     if (!fp)
00133     {
00134         Log.tinyprintf("Unable to open %s for writing." ENDLINE, buffer);
00135         return;
00136     }
00137     DebugTotalFiles++;
00138     fprintf(fp, "*** Begin CHANNELS ***\n");
00139     save_channels(fp);
00140 
00141     fprintf(fp, "*** Begin COMSYS ***\n");
00142     save_comsystem(fp);
00143 
00144     if (fclose(fp) == 0)
00145     {
00146         DebugTotalFiles--;
00147     }
00148     ReplaceFile(buffer, filename);
00149 }
00150 
00151 // Aliases must be between 1 and 5 characters. No spaces. No ANSI.
00152 //
00153 static char *MakeCanonicalComAlias
00154 (
00155     const char *pAlias,
00156     int *nValidAlias,
00157     bool *bValidAlias
00158 )
00159 {
00160     static char Buffer[ALIAS_SIZE];
00161     *nValidAlias = 0;
00162     *bValidAlias = false;
00163 
00164     if (!pAlias)
00165     {
00166         return NULL;
00167     }
00168     const char *p = pAlias;
00169     char *q = Buffer;
00170     int n = 0;
00171     while (*p)
00172     {
00173         if (  !mux_isprint(*p)
00174            || *p == ' ')
00175         {
00176             return NULL;
00177         }
00178         if (  n <= MAX_ALIAS_LEN
00179            && q < Buffer + ALIAS_SIZE)
00180         {
00181             n++;
00182             *q++ = *p;
00183         }
00184         p++;
00185     }
00186     *q = '\0';
00187     if (  n < 1
00188        || MAX_ALIAS_LEN < n)
00189     {
00190         return NULL;
00191     }
00192     *nValidAlias = n;
00193     *bValidAlias = true;
00194     return Buffer;
00195 }
00196 
00197 static bool ParseChannelLine(char *pBuffer, char *pAlias5, char **ppChannelName)
00198 {
00199     // Fetch alias portion. We need to find the first space.
00200     //
00201     char *p = strchr(pBuffer, ' ');
00202     if (!p)
00203     {
00204         return false;
00205     }
00206 
00207     *p = '\0';
00208     bool bValidAlias;
00209     int  nValidAlias;
00210     char *pValidAlias = MakeCanonicalComAlias(pBuffer, &nValidAlias, &bValidAlias);
00211     if (!bValidAlias)
00212     {
00213         return false;
00214     }
00215     strcpy(pAlias5, pValidAlias);
00216 
00217     // Skip any leading space before the channel name.
00218     //
00219     p++;
00220     while (mux_isspace(*p))
00221     {
00222         p++;
00223     }
00224 
00225     if (*p == '\0')
00226     {
00227         return false;
00228     }
00229 
00230     // The rest of the line is the channel name.
00231     //
00232     *ppChannelName = StringClone(p);
00233     return true;
00234 }
00235 
00236 void load_channels(FILE *fp)
00237 {
00238     int i, j;
00239     char buffer[LBUF_SIZE];
00240     comsys_t *c;
00241 
00242     int np = 0;
00243     int cc = fscanf(fp, "%d\n", &np);
00244     mux_assert(1 == cc);
00245     for (i = 0; i < np; i++)
00246     {
00247         c = create_new_comsys();
00248         c->who = 0;
00249         c->numchannels = 0;
00250         cc = fscanf(fp, "%d %d\n", &(c->who), &(c->numchannels));
00251         mux_assert(2 == cc);
00252         c->maxchannels = c->numchannels;
00253         if (c->maxchannels > 0)
00254         {
00255             c->alias = (char *)MEMALLOC(c->maxchannels * ALIAS_SIZE);
00256             ISOUTOFMEMORY(c->alias);
00257             c->channels = (char **)MEMALLOC(sizeof(char *) * c->maxchannels);
00258             ISOUTOFMEMORY(c->channels);
00259 
00260             for (j = 0; j < c->numchannels; j++)
00261             {
00262                 int n = GetLineTrunc(buffer, sizeof(buffer), fp);
00263                 if (buffer[n-1] == '\n')
00264                 {
00265                     // Get rid of trailing '\n'.
00266                     //
00267                     n--;
00268                     buffer[n] = '\0';
00269                 }
00270                 if (!ParseChannelLine(buffer, c->alias + j * ALIAS_SIZE, c->channels+j))
00271                 {
00272                     c->numchannels--;
00273                     j--;
00274                 }
00275             }
00276             sort_com_aliases(c);
00277         }
00278         else
00279         {
00280             c->alias = NULL;
00281             c->channels = NULL;
00282         }
00283         if (Good_obj(c->who))
00284         {
00285             add_comsys(c);
00286         }
00287         else
00288         {
00289             Log.tinyprintf("Invalid dbref %d." ENDLINE, c->who);
00290         }
00291         purge_comsystem();
00292     }
00293 }
00294 
00295 void purge_comsystem(void)
00296 {
00297 #ifdef ABORT_PURGE_COMSYS
00298     return;
00299 #endif // ABORT_PURGE_COMSYS
00300 
00301     comsys_t *c;
00302     comsys_t *d;
00303     int i;
00304     for (i = 0; i < NUM_COMSYS; i++)
00305     {
00306         c = comsys_table[i];
00307         while (c)
00308         {
00309             d = c;
00310             c = c->next;
00311             if (d->numchannels == 0)
00312             {
00313                 del_comsys(d->who);
00314                 continue;
00315             }
00316             if (isPlayer(d->who))
00317             {
00318                 continue;
00319             }
00320             if (  God(Owner(d->who))
00321                && Going(d->who))
00322             {
00323                 del_comsys(d->who);
00324                 continue;
00325             }
00326         }
00327     }
00328 }
00329 
00330 void save_channels(FILE *fp)
00331 {
00332     purge_comsystem();
00333 
00334     comsys_t *c;
00335     int i, j;
00336     int np = 0;
00337     for (i = 0; i < NUM_COMSYS; i++)
00338     {
00339         c = comsys_table[i];
00340         while (c)
00341         {
00342             np++;
00343             c = c->next;
00344         }
00345     }
00346 
00347     fprintf(fp, "%d\n", np);
00348     for (i = 0; i < NUM_COMSYS; i++)
00349     {
00350         c = comsys_table[i];
00351         while (c)
00352         {
00353             fprintf(fp, "%d %d\n", c->who, c->numchannels);
00354             for (j = 0; j < c->numchannels; j++)
00355             {
00356                 fprintf(fp, "%s %s\n", c->alias + j * ALIAS_SIZE, c->channels[j]);
00357             }
00358             c = c->next;
00359         }
00360     }
00361 }
00362 
00363 comsys_t *create_new_comsys(void)
00364 {
00365     comsys_t *c = (comsys_t *)MEMALLOC(sizeof(comsys_t));
00366     ISOUTOFMEMORY(c);
00367 
00368     c->who         = NOTHING;
00369     c->numchannels = 0;
00370     c->maxchannels = 0;
00371     c->alias       = NULL;
00372     c->channels    = NULL;
00373     c->next        = NULL;
00374     return c;
00375 }
00376 
00377 static comsys_t *get_comsys(dbref which)
00378 {
00379     if (which < 0)
00380     {
00381         return NULL;
00382     }
00383 
00384     comsys_t *c = comsys_table[which % NUM_COMSYS];
00385 
00386     while (c && (c->who != which))
00387         c = c->next;
00388 
00389     if (!c)
00390     {
00391         c = create_new_comsys();
00392         c->who = which;
00393         add_comsys(c);
00394     }
00395     return c;
00396 }
00397 
00398 void add_comsys(comsys_t *c)
00399 {
00400     if (c->who < 0 || c->who >= mudstate.db_top)
00401     {
00402         Log.tinyprintf("add_comsys: dbref %d out of range [0, %d)" ENDLINE, c->who, mudstate.db_top);
00403         return;
00404     }
00405 
00406     c->next = comsys_table[c->who % NUM_COMSYS];
00407     comsys_table[c->who % NUM_COMSYS] = c;
00408 }
00409 
00410 void del_comsys(dbref who)
00411 {
00412     if (who < 0 || who >= mudstate.db_top)
00413     {
00414         Log.tinyprintf("del_comsys: dbref %d out of range [0, %d)" ENDLINE, who, mudstate.db_top);
00415         return;
00416     }
00417 
00418     comsys_t *c = comsys_table[who % NUM_COMSYS];
00419 
00420     if (c == NULL)
00421     {
00422         return;
00423     }
00424 
00425     if (c->who == who)
00426     {
00427         comsys_table[who % NUM_COMSYS] = c->next;
00428         destroy_comsys(c);
00429         return;
00430     }
00431     comsys_t *last = c;
00432     c = c->next;
00433     while (c)
00434     {
00435         if (c->who == who)
00436         {
00437             last->next = c->next;
00438             destroy_comsys(c);
00439             return;
00440         }
00441         last = c;
00442         c = c->next;
00443     }
00444 }
00445 
00446 void destroy_comsys(comsys_t *c)
00447 {
00448     int i;
00449 
00450     if (c->alias)
00451     {
00452         MEMFREE(c->alias);
00453         c->alias = NULL;
00454     }
00455     for (i = 0; i < c->numchannels; i++)
00456     {
00457         MEMFREE(c->channels[i]);
00458         c->channels[i] = NULL;
00459     }
00460     if (c->channels)
00461     {
00462         MEMFREE(c->channels);
00463         c->channels = NULL;
00464     }
00465     MEMFREE(c);
00466     c = NULL;
00467 }
00468 
00469 void sort_com_aliases(comsys_t *c)
00470 {
00471     int i;
00472     char buffer[10];
00473     char *s;
00474     bool cont = true;
00475 
00476     while (cont)
00477     {
00478         cont = false;
00479         for (i = 0; i < c->numchannels - 1; i++)
00480         {
00481             if (strcmp(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE) > 0)
00482             {
00483                 strcpy(buffer, c->alias + i * ALIAS_SIZE);
00484                 strcpy(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE);
00485                 strcpy(c->alias + (i + 1) * ALIAS_SIZE, buffer);
00486                 s = c->channels[i];
00487                 c->channels[i] = c->channels[i + 1];
00488                 c->channels[i + 1] = s;
00489                 cont = true;
00490             }
00491         }
00492     }
00493 }
00494 
00495 static char *get_channel_from_alias(dbref player, char *alias)
00496 {
00497     int first, last, current, dir;
00498 
00499     comsys_t *c = get_comsys(player);
00500 
00501     current = first = 0;
00502     last = c->numchannels - 1;
00503     dir = 1;
00504 
00505     while (dir && (first <= last))
00506     {
00507         current = (first + last) / 2;
00508         dir = strcmp(alias, c->alias + ALIAS_SIZE * current);
00509         if (dir < 0)
00510             last = current - 1;
00511         else
00512             first = current + 1;
00513     }
00514 
00515     if (!dir)
00516     {
00517         return c->channels[current];
00518     }
00519     else
00520     {
00521         return "";
00522     }
00523 }
00524 
00525 void load_comsystem(FILE *fp)
00526 {
00527     int i, j, dummy;
00528     int ver = 0;
00529     struct channel *ch;
00530     char temp[LBUF_SIZE];
00531 
00532     num_channels = 0;
00533 
00534     int nc = 0;
00535     fgets(temp, sizeof(temp), fp);
00536     if (!strncmp(temp, "+V", 2))
00537     {
00538         // +V2 has colored headers
00539         //
00540         ver = mux_atol(temp + 2);
00541         if (ver < 1 || 3 < ver)
00542         {
00543             return;
00544         }
00545         int cc;
00546         cc = fscanf(fp, "%d\n", &nc);
00547         mux_assert(1 == cc);
00548     }
00549     else
00550     {
00551         nc = mux_atol(temp);
00552     }
00553 
00554     num_channels = nc;
00555 
00556     for (i = 0; i < nc; i++)
00557     {
00558         ch = (struct channel *)MEMALLOC(sizeof(struct channel));
00559         ISOUTOFMEMORY(ch);
00560 
00561         int nChannel = GetLineTrunc(temp, sizeof(temp), fp);
00562         if (nChannel > MAX_CHANNEL_LEN)
00563         {
00564             nChannel = MAX_CHANNEL_LEN;
00565         }
00566         if (temp[nChannel-1] == '\n')
00567         {
00568             // Get rid of trailing '\n'.
00569             //
00570             nChannel--;
00571         }
00572         memcpy(ch->name, temp, nChannel);
00573         ch->name[nChannel] = '\0';
00574 
00575         if (ver >= 2)
00576         {
00577             int nHeader = GetLineTrunc(temp, sizeof(temp), fp);
00578             if (nHeader > MAX_HEADER_LEN)
00579             {
00580                 nHeader = MAX_HEADER_LEN;
00581             }
00582             if (temp[nHeader-1] == '\n')
00583             {
00584                 nHeader--;
00585             }
00586             memcpy(ch->header, temp, nHeader);
00587             ch->header[nHeader] = '\0';
00588         }
00589 
00590         ch->on_users = NULL;
00591 
00592         hashaddLEN(ch->name, nChannel, ch, &mudstate.channel_htab);
00593 
00594         ch->type         = 127;
00595         ch->temp1        = 0;
00596         ch->temp2        = 0;
00597         ch->charge       = 0;
00598         ch->charge_who   = NOTHING;
00599         ch->amount_col   = 0;
00600         ch->num_messages = 0;
00601         ch->chan_obj     = NOTHING;
00602 
00603         int cc;
00604         if (ver >= 1)
00605         {
00606             cc = fscanf(fp, "%d %d %d %d %d %d %d %d\n",
00607                 &(ch->type), &(ch->temp1), &(ch->temp2),
00608                 &(ch->charge), &(ch->charge_who),
00609                 &(ch->amount_col), &(ch->num_messages), &(ch->chan_obj));
00610             mux_assert(8 == cc);
00611         }
00612         else
00613         {
00614             cc = fscanf(fp, "%d %d %d %d %d %d %d %d %d %d\n",
00615                 &(ch->type), &(dummy), &(ch->temp1), &(ch->temp2),
00616                 &(dummy), &(ch->charge), &(ch->charge_who),
00617                 &(ch->amount_col), &(ch->num_messages), &(ch->chan_obj));
00618             mux_assert(10 == cc);
00619         }
00620 
00621         if (ver <= 1)
00622         {
00623             // Build colored header if not +V2 or later db.
00624             //
00625             if (ch->type & CHANNEL_PUBLIC)
00626             {
00627                 sprintf(temp, "%s[%s%s%s%s%s]%s", ANSI_CYAN, ANSI_HILITE,
00628                     ANSI_BLUE, ch->name, ANSI_NORMAL, ANSI_CYAN, ANSI_NORMAL);
00629             }
00630             else
00631             {
00632                 sprintf(temp, "%s[%s%s%s%s%s]%s", ANSI_MAGENTA, ANSI_HILITE,
00633                     ANSI_RED, ch->name, ANSI_NORMAL, ANSI_MAGENTA,
00634                     ANSI_NORMAL);
00635             }
00636             int vwVisual;
00637             ANSI_TruncateToField(temp, MAX_HEADER_LEN+1, ch->header,
00638                 MAX_HEADER_LEN+1, &vwVisual, ANSI_ENDGOAL_NORMAL);
00639         }
00640 
00641         ch->num_users = 0;
00642         cc =fscanf(fp, "%d\n", &(ch->num_users));
00643         mux_assert(1 == cc);
00644         ch->max_users = ch->num_users;
00645         if (ch->num_users > 0)
00646         {
00647             ch->users = (struct comuser **)calloc(ch->max_users, sizeof(struct comuser *));
00648             ISOUTOFMEMORY(ch->users);
00649 
00650             int jAdded = 0;
00651             for (j = 0; j < ch->num_users; j++)
00652             {
00653                 struct comuser t_user;
00654                 memset(&t_user, 0, sizeof(t_user));
00655 
00656                 t_user.who = NOTHING;
00657                 t_user.bUserIsOn = false;
00658                 t_user.ComTitleStatus = false;
00659 
00660                 int iUserIsOn;
00661                 if (ver == 3)
00662                 {
00663                     int iComTitleStatus;
00664                     cc = fscanf(fp, "%d %d %d\n", &(t_user.who), &iUserIsOn,
00665                         &iComTitleStatus);
00666                     mux_assert(3 == cc);
00667                     t_user.bUserIsOn = (iUserIsOn ? true : false);
00668                     t_user.ComTitleStatus = (iComTitleStatus ? true : false);
00669                 }
00670                 else
00671                 {
00672                     t_user.ComTitleStatus = true;
00673                     if (ver)
00674                     {
00675                         cc = fscanf(fp, "%d %d\n", &(t_user.who), &iUserIsOn);
00676                         mux_assert(2 == cc);
00677                         t_user.bUserIsOn = (iUserIsOn ? true : false);
00678                     }
00679                     else
00680                     {
00681                         cc = fscanf(fp, "%d %d %d", &(t_user.who), &(dummy), &(dummy));
00682                         mux_assert(3 == cc);
00683                         cc = fscanf(fp, "%d\n", &iUserIsOn);
00684                         mux_assert(1 == cc);
00685                         t_user.bUserIsOn = (iUserIsOn ? true : false);
00686                     }
00687                 }
00688 
00689                 // Read Comtitle.
00690                 //
00691                 int nTitle = GetLineTrunc(temp, sizeof(temp), fp);
00692                 char *pTitle = temp;
00693 
00694                 if (!Good_dbref(t_user.who))
00695                 {
00696                     Log.tinyprintf("load_comsystem: dbref %d out of range [0, %d)." ENDLINE, t_user.who, mudstate.db_top);
00697                 }
00698                 else if (isGarbage(t_user.who))
00699                 {
00700                     Log.tinyprintf("load_comsystem: dbref is GARBAGE." ENDLINE, t_user.who);
00701                 }
00702                 else
00703                 {
00704                     // Validate comtitle
00705                     //
00706                     if (3 < nTitle && temp[0] == 't' && temp[1] == ':')
00707                     {
00708                         pTitle = temp+2;
00709                         nTitle -= 2;
00710                         if (pTitle[nTitle-1] == '\n')
00711                         {
00712                             // Get rid of trailing '\n'.
00713                             //
00714                             nTitle--;
00715                         }
00716                         if (nTitle <= 0 || MAX_TITLE_LEN < nTitle)
00717                         {
00718                             nTitle = 0;
00719                             pTitle = temp;
00720                         }
00721                     }
00722                     else
00723                     {
00724                         nTitle = 0;
00725                     }
00726 
00727                     struct comuser *user = (struct comuser *)MEMALLOC(sizeof(struct comuser));
00728                     ISOUTOFMEMORY(user);
00729                     memcpy(user, &t_user, sizeof(struct comuser));
00730 
00731                     user->title = StringCloneLen(pTitle, nTitle);
00732                     ch->users[jAdded++] = user;
00733 
00734                     if (  !(isPlayer(user->who))
00735                        && !(Going(user->who)
00736                        && (God(Owner(user->who)))))
00737                     {
00738                         do_joinchannel(user->who, ch);
00739                     }
00740                     user->on_next = ch->on_users;
00741                     ch->on_users = user;
00742                 }
00743             }
00744             ch->num_users = jAdded;
00745             sort_users(ch);
00746         }
00747         else
00748         {
00749             ch->users = NULL;
00750         }
00751     }
00752 }
00753 
00754 void save_comsystem(FILE *fp)
00755 {
00756     struct channel *ch;
00757     struct comuser *user;
00758     int j;
00759 
00760     fprintf(fp, "+V3\n");
00761     fprintf(fp, "%d\n", num_channels);
00762     for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
00763          ch;
00764          ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
00765     {
00766         fprintf(fp, "%s\n", ch->name);
00767         fprintf(fp, "%s\n", ch->header);
00768 
00769         fprintf(fp, "%d %d %d %d %d %d %d %d\n", ch->type, ch->temp1,
00770             ch->temp2, ch->charge, ch->charge_who, ch->amount_col,
00771             ch->num_messages, ch->chan_obj);
00772 
00773         // Count the number of 'valid' users to dump.
00774         //
00775         int nUsers = 0;
00776         for (j = 0; j < ch->num_users; j++)
00777         {
00778             user = ch->users[j];
00779             if (user->who >= 0 && user->who < mudstate.db_top)
00780             {
00781                 nUsers++;
00782             }
00783         }
00784 
00785         fprintf(fp, "%d\n", nUsers);
00786         for (j = 0; j < ch->num_users; j++)
00787         {
00788             user = ch->users[j];
00789             if (user->who >= 0 && user->who < mudstate.db_top)
00790             {
00791                 user = ch->users[j];
00792                 fprintf(fp, "%d %d %d\n", user->who, user->bUserIsOn, user->ComTitleStatus);
00793                 if (user->title[0] != '\0')
00794                 {
00795                     fprintf(fp, "t:%s\n", user->title);
00796                 }
00797                 else
00798                 {
00799                     fprintf(fp, "t:\n");
00800                 }
00801             }
00802         }
00803     }
00804 }
00805 
00806 static void BuildChannelMessage
00807 (
00808     bool bSpoof,
00809     const char *pHeader,
00810     struct comuser *user,
00811     char *pPose,
00812     char **messNormal,
00813     char **messNoComtitle
00814 )
00815 {
00816     // Allocate necessary buffers.
00817     //
00818     *messNormal = alloc_lbuf("BCM.messNormal");
00819     *messNoComtitle = NULL;
00820     if (!bSpoof)
00821     {
00822         *messNoComtitle = alloc_lbuf("BCM.messNoComtitle");
00823     }
00824 
00825     // Comtitle Check
00826     //
00827     bool hasComTitle = (user->title[0] != '\0');
00828 
00829     char *mnptr  = *messNormal;     // Message without comtitle removal
00830     char *mncptr = *messNoComtitle; // Message with comtitle removal
00831 
00832     safe_str(pHeader, *messNormal, &mnptr);
00833     safe_chr(' ', *messNormal, &mnptr);
00834     if (!bSpoof)
00835     {
00836         safe_str(pHeader, *messNoComtitle, &mncptr);
00837         safe_chr(' ', *messNoComtitle, &mncptr);
00838     }
00839 
00840     // Don't evaluate a title if there isn't one to parse or evaluation of
00841     // comtitles is disabled.
00842     // If they're set spoof, ComTitleStatus doesn't matter.
00843     if (hasComTitle && (user->ComTitleStatus || bSpoof))
00844     {
00845         if (mudconf.eval_comtitle)
00846         {
00847             // Evaluate the comtitle as code.
00848             //
00849             char TempToEval[LBUF_SIZE];
00850             strcpy(TempToEval, user->title);
00851             char *q = TempToEval;
00852             mux_exec(*messNormal, &mnptr, user->who, user->who, user->who,
00853                 EV_FCHECK | EV_EVAL | EV_TOP, &q, (char **)NULL, 0);
00854         }
00855         else
00856         {
00857             safe_str(user->title, *messNormal, &mnptr);
00858         }
00859         if (!bSpoof)
00860         {
00861             safe_chr(' ', *messNormal, &mnptr);
00862             safe_str(Moniker(user->who), *messNormal, &mnptr);
00863             safe_str(Moniker(user->who), *messNoComtitle, &mncptr);
00864         }
00865     }
00866     else
00867     {
00868         safe_str(Moniker(user->who), *messNormal, &mnptr);
00869         if (!bSpoof)
00870         {
00871             safe_str(Moniker(user->who), *messNoComtitle, &mncptr);
00872         }
00873     }
00874 
00875     char *saystring = NULL;
00876     char *newPose = NULL;
00877 
00878     switch(pPose[0])
00879     {
00880     case ':':
00881         pPose++;
00882         newPose = modSpeech(user->who, pPose, true, "channel/pose");
00883         if (newPose)
00884         {
00885             pPose = newPose;
00886         }
00887         safe_chr(' ', *messNormal, &mnptr);
00888         safe_str(pPose, *messNormal, &mnptr);
00889         if (!bSpoof)
00890         {
00891             safe_chr(' ', *messNoComtitle, &mncptr);
00892             safe_str(pPose, *messNoComtitle, &mncptr);
00893         }
00894         break;
00895 
00896     case ';':
00897         pPose++;
00898         newPose = modSpeech(user->who, pPose, true, "channel/pose");
00899         if (newPose)
00900         {
00901             pPose = newPose;
00902         }
00903         safe_str(pPose, *messNormal, &mnptr);
00904         if (!bSpoof)
00905         {
00906             safe_str(pPose, *messNoComtitle, &mncptr);
00907         }
00908         break;
00909 
00910     default:
00911         newPose = modSpeech(user->who, pPose, true, "channel");
00912         if (newPose)
00913         {
00914             pPose = newPose;
00915         }
00916         saystring = modSpeech(user->who, pPose, false, "channel");
00917         if (saystring)
00918         {
00919             safe_chr(' ', *messNormal, &mnptr);
00920             safe_str(saystring, *messNormal, &mnptr);
00921             safe_str(" \"", *messNormal, &mnptr);
00922         }
00923         else
00924         {
00925             safe_str(" says, \"", *messNormal, &mnptr);
00926         }
00927         safe_str(pPose, *messNormal, &mnptr);
00928         safe_chr('"', *messNormal, &mnptr);
00929         if (!bSpoof)
00930         {
00931             if (saystring)
00932             {
00933                 safe_chr(' ', *messNoComtitle, &mncptr);
00934                 safe_str(saystring, *messNoComtitle, &mncptr);
00935                 safe_str(" \"", *messNoComtitle, &mncptr);
00936             }
00937             else
00938             {
00939                 safe_str(" says, \"", *messNoComtitle, &mncptr);
00940             }
00941             safe_str(pPose, *messNoComtitle, &mncptr);
00942             safe_chr('"', *messNoComtitle, &mncptr);
00943         }
00944         break;
00945     }
00946     *mnptr = '\0';
00947     if (!bSpoof)
00948     {
00949         *mncptr = '\0';
00950     }
00951     if (newPose)
00952     {
00953         free_lbuf(newPose);
00954     }
00955     if (saystring)
00956     {
00957         free_lbuf(saystring);
00958     }
00959 }
00960 
00961 static void do_processcom(dbref player, char *arg1, char *arg2)
00962 {
00963     if (!*arg2)
00964     {
00965         raw_notify(player, "No message.");
00966         return;
00967     }
00968     if (3500 < strlen(arg2))
00969     {
00970         arg2[3500] = '\0';
00971     }
00972     struct channel *ch = select_channel(arg1);
00973     if (!ch)
00974     {
00975         raw_notify(player, tprintf("Unknown channel %s.", arg1));
00976         return;
00977     }
00978     struct comuser *user = select_user(ch, player);
00979     if (!user)
00980     {
00981         raw_notify(player, "You are not listed as on that channel.  Delete this alias and readd.");
00982         return;
00983     }
00984     if (  Gagged(player)
00985        && !Wizard(player))
00986     {
00987         raw_notify(player, "GAGGED players may not speak on channels.");
00988         return;
00989     }
00990     if (!strcmp(arg2, "on"))
00991     {
00992         do_joinchannel(player, ch);
00993     }
00994     else if (!strcmp(arg2, "off"))
00995     {
00996         do_leavechannel(player, ch);
00997     }
00998     else if (!user->bUserIsOn)
00999     {
01000         raw_notify(player, tprintf("You must be on %s to do that.", arg1));
01001         return;
01002     }
01003     else if (!strcmp(arg2, "who"))
01004     {
01005         do_comwho(player, ch);
01006     }
01007     else if (  !strncmp(arg2, "last", 4)
01008             && (  arg2[4] == '\0'
01009                || (  arg2[4] == ' '
01010                   && is_integer(arg2 + 5, NULL))))
01011     {
01012         // Parse optional number after the 'last' command.
01013         //
01014         int nRecall = DFLT_RECALL_REQUEST;
01015         if (arg2[4] == ' ')
01016         {
01017             nRecall = mux_atol(arg2 + 5);
01018         }
01019         do_comlast(player, ch, nRecall);
01020     }
01021     else if (!test_transmit_access(player, ch))
01022     {
01023         raw_notify(player, "That channel type cannot be transmitted on.");
01024         return;
01025     }
01026     else
01027     {
01028         if (!payfor(player, Guest(player) ? 0 : ch->charge))
01029         {
01030             notify(player, tprintf("You don't have enough %s.", mudconf.many_coins));
01031             return;
01032         }
01033         else
01034         {
01035             ch->amount_col += ch->charge;
01036             giveto(ch->charge_who, ch->charge);
01037         }
01038 
01039         // BuildChannelMessage allocates messNormal and messNoComtitle,
01040         // SendChannelMessage frees them.
01041         //
01042         char *messNormal;
01043         char *messNoComtitle;
01044         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user,
01045             arg2, &messNormal, &messNoComtitle);
01046         SendChannelMessage(player, ch, messNormal, messNoComtitle);
01047     }
01048 }
01049 
01050 void SendChannelMessage
01051 (
01052     dbref executor,
01053     struct channel *ch,
01054     char *msgNormal,
01055     char *msgNoComtitle
01056 )
01057 {
01058     bool bSpoof = ((ch->type & CHANNEL_SPOOF) != 0);
01059     ch->num_messages++;
01060 
01061     struct comuser *user;
01062     for (user = ch->on_users; user; user = user->on_next)
01063     {
01064         if (  user->bUserIsOn
01065            && test_receive_access(user->who, ch))
01066         {
01067             if (  user->ComTitleStatus
01068                || bSpoof
01069                || msgNoComtitle == NULL)
01070             {
01071                 notify_with_cause_ooc(user->who, executor, msgNormal);
01072             }
01073             else
01074             {
01075                 notify_with_cause_ooc(user->who, executor, msgNoComtitle);
01076             }
01077         }
01078     }
01079 
01080     dbref obj = ch->chan_obj;
01081     if (Good_obj(obj))
01082     {
01083         dbref aowner;
01084         int aflags;
01085         int logmax = DFLT_MAX_LOG;
01086         char *maxbuf;
01087         ATTR *pattr = atr_str("MAX_LOG");
01088         if (  pattr
01089            && pattr->number)
01090         {
01091             maxbuf = atr_get(obj, pattr->number, &aowner, &aflags);
01092             logmax = mux_atol(maxbuf);
01093             free_lbuf(maxbuf);
01094         }
01095         if (logmax > 0)
01096         {
01097             if (logmax > MAX_RECALL_REQUEST)
01098             {
01099                 logmax = MAX_RECALL_REQUEST;
01100                 atr_add(ch->chan_obj, pattr->number, mux_ltoa_t(logmax), GOD,
01101                     AF_CONST|AF_NOPROG|AF_NOPARSE);
01102             }
01103             char *p = tprintf("HISTORY_%d", iMod(ch->num_messages, logmax));
01104             int atr = mkattr(GOD, p);
01105             if (0 < atr)
01106             {
01107                 atr_add(ch->chan_obj, atr, msgNormal, GOD, AF_CONST|AF_NOPROG|AF_NOPARSE);
01108             }
01109         }
01110     }
01111     else if (ch->chan_obj != NOTHING)
01112     {
01113         ch->chan_obj = NOTHING;
01114     }
01115 
01116     // Since msgNormal and msgNoComTitle are no longer needed, free them here.
01117     //
01118     if (msgNormal)
01119     {
01120         free_lbuf(msgNormal);
01121     }
01122     if (  msgNoComtitle
01123        && msgNoComtitle != msgNormal)
01124     {
01125         free_lbuf(msgNoComtitle);
01126     }
01127 }
01128 
01129 void do_joinchannel(dbref player, struct channel *ch)
01130 {
01131     struct comuser **cu;
01132     int i;
01133 
01134     struct comuser *user = select_user(ch, player);
01135 
01136     if (!user)
01137     {
01138         ch->num_users++;
01139         if (ch->num_users >= ch->max_users)
01140         {
01141             ch->max_users += 10;
01142             cu = (struct comuser **)MEMALLOC(sizeof(struct comuser *) * ch->max_users);
01143             ISOUTOFMEMORY(cu);
01144 
01145             for (i = 0; i < (ch->num_users - 1); i++)
01146             {
01147                 cu[i] = ch->users[i];
01148             }
01149             MEMFREE(ch->users);
01150             ch->users = cu;
01151         }
01152         user = (struct comuser *)MEMALLOC(sizeof(struct comuser));
01153         ISOUTOFMEMORY(user);
01154 
01155         for (i = ch->num_users - 1; i > 0 && ch->users[i - 1]->who > player; i--)
01156         {
01157             ch->users[i] = ch->users[i - 1];
01158         }
01159         ch->users[i] = user;
01160 
01161         user->who            = player;
01162         user->bUserIsOn      = true;
01163         user->ComTitleStatus = true;
01164         user->title          = StringClone("");
01165 
01166         // if (Connected(player))&&(isPlayer(player))
01167         //
01168         if (UNDEAD(player))
01169         {
01170             user->on_next = ch->on_users;
01171             ch->on_users  = user;
01172         }
01173     }
01174     else if (!user->bUserIsOn)
01175     {
01176         user->bUserIsOn = true;
01177     }
01178     else
01179     {
01180         raw_notify(player, tprintf("You are already on channel %s.", ch->name));
01181         return;
01182     }
01183 
01184     if (!Hidden(player))
01185     {
01186         char *messNormal, *messNoComtitle;
01187         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user,
01188             ":has joined this channel.", &messNormal, &messNoComtitle);
01189         SendChannelMessage(player, ch, messNormal, messNoComtitle);
01190     }
01191 }
01192 
01193 void do_leavechannel(dbref player, struct channel *ch)
01194 {
01195     struct comuser *user = select_user(ch, player);
01196     raw_notify(player, tprintf("You have left channel %s.", ch->name));
01197     if (  user->bUserIsOn
01198        && !Hidden(player))
01199     {
01200         char *messNormal, *messNoComtitle;
01201         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user,
01202             ":has left this channel.", &messNormal, &messNoComtitle);
01203         SendChannelMessage(player, ch, messNormal, messNoComtitle);
01204     }
01205     user->bUserIsOn = false;
01206 }
01207 
01208 static void do_comwho_line
01209 (
01210     dbref player,
01211     struct channel *ch,
01212     struct comuser *user
01213 )
01214 {
01215     char *msg;
01216     char *buff = NULL;
01217 
01218     if (user->title[0] != '\0')
01219     {
01220         // There is a comtitle
01221         //
01222         if (Staff(player))
01223         {
01224             buff = unparse_object(player, user->who, false);
01225             if (ch->type & CHANNEL_SPOOF)
01226             {
01227                 msg = tprintf("%s as %s", buff, user->title);
01228             }
01229             else
01230             {
01231                 msg = tprintf("%s as %s %s", buff, user->title, buff);
01232             }
01233         }
01234         else
01235         {
01236             if (ch->type & CHANNEL_SPOOF)
01237             {
01238                 msg = user->title;
01239             }
01240             else
01241             {
01242                 buff = unparse_object(player, user->who, false);
01243                 msg = tprintf("%s %s", user->title, buff);
01244             }
01245         }
01246     }
01247     else
01248     {
01249         buff = unparse_object(player, user->who, false);
01250         msg = buff;
01251     }
01252 
01253     raw_notify(player, msg);
01254     if (buff)
01255     {
01256         free_lbuf(buff);
01257     }
01258 }
01259 
01260 void do_comwho(dbref player, struct channel *ch)
01261 {
01262     struct comuser *user;
01263 
01264     raw_notify(player, "-- Players --");
01265     for (user = ch->on_users; user; user = user->on_next)
01266     {
01267         if (isPlayer(user->who))
01268         {
01269             if (  Connected(user->who)
01270                && (  !Hidden(user->who)
01271                   || Wizard_Who(player)
01272                   || See_Hidden(player)))
01273             {
01274                 if (user->bUserIsOn)
01275                 {
01276                     do_comwho_line(player, ch, user);
01277                 }
01278             }
01279             else if (!Hidden(user->who))
01280             {
01281                 do_comdisconnectchannel(user->who, ch->name);
01282             }
01283         }
01284     }
01285     raw_notify(player, "-- Objects --");
01286     for (user = ch->on_users; user; user = user->on_next)
01287     {
01288         if (!isPlayer(user->who))
01289         {
01290             if (  Going(user->who)
01291                && God(Owner(user->who)))
01292             {
01293                 do_comdisconnectchannel(user->who, ch->name);
01294             }
01295             else if (user->bUserIsOn)
01296             {
01297                 do_comwho_line(player, ch, user);
01298             }
01299         }
01300     }
01301     raw_notify(player, tprintf("-- %s --", ch->name));
01302 }
01303 
01304 void do_comlast(dbref player, struct channel *ch, int arg)
01305 {
01306     if (!Good_obj(ch->chan_obj))
01307     {
01308         raw_notify(player, "Channel does not have an object.");
01309         return;
01310     }
01311     dbref aowner;
01312     int aflags;
01313     dbref obj = ch->chan_obj;
01314     int logmax = MAX_RECALL_REQUEST;
01315     ATTR *pattr = atr_str("MAX_LOG");
01316     if (  pattr
01317        && (atr_get_info(obj, pattr->number, &aowner, &aflags)))
01318     {
01319         char *maxbuf = atr_get(obj, pattr->number, &aowner, &aflags);
01320         logmax = mux_atol(maxbuf);
01321         free_lbuf(maxbuf);
01322     }
01323     if (logmax < 1)
01324     {
01325         raw_notify(player, "Channel does not log.");
01326         return;
01327     }
01328     if (arg < MIN_RECALL_REQUEST)
01329     {
01330         arg = MIN_RECALL_REQUEST;
01331     }
01332     if (arg > logmax)
01333     {
01334         arg = logmax;
01335     }
01336 
01337     char *message;
01338     int histnum = ch->num_messages - arg;
01339 
01340     raw_notify(player, "-- Begin Comsys Recall --");
01341     for (int count = 0; count < arg; count++)
01342     {
01343         histnum++;
01344         pattr = atr_str(tprintf("HISTORY_%d", iMod(histnum, logmax)));
01345         if (pattr)
01346         {
01347             message = atr_get(obj, pattr->number, &aowner, &aflags);
01348             raw_notify(player, message);
01349             free_lbuf(message);
01350         }
01351     }
01352     raw_notify(player, "-- End Comsys Recall --");
01353 }
01354 
01355 static bool do_chanlog(dbref player, char *channel, char *arg)
01356 {
01357     UNUSED_PARAMETER(player);
01358 
01359     int value;
01360     if (  !*arg
01361        || !is_integer(arg, NULL)
01362        || (value = mux_atol(arg)) > MAX_RECALL_REQUEST)
01363     {
01364         return false;
01365     }
01366     if (value < 0)
01367     {
01368         value = 0;
01369     }
01370     struct channel *ch = select_channel(channel);
01371     if (!Good_obj(ch->chan_obj))
01372     {
01373         // No channel object has been set.
01374         //
01375         return false;
01376     }
01377     int atr = mkattr(GOD, "MAX_LOG");
01378     if (atr <= 0)
01379     {
01380         return false;
01381     }
01382     dbref aowner;
01383     int aflags;
01384     char *oldvalue = atr_get(ch->chan_obj, atr, &aowner, &aflags);
01385     if (oldvalue)
01386     {
01387         int oldnum = mux_atol(oldvalue);
01388         if (oldnum > value)
01389         {
01390             ATTR *hist;
01391             for (int count = 0; count <= oldnum; count++)
01392             {
01393                 hist = atr_str(tprintf("HISTORY_%d", count));
01394                 if (hist)
01395                 {
01396                     atr_clr(ch->chan_obj, hist->number);
01397                 }
01398             }
01399         }
01400         free_lbuf(oldvalue);
01401     }
01402     atr_add(ch->chan_obj, atr, mux_ltoa_t(value), GOD,
01403         AF_CONST|AF_NOPROG|AF_NOPARSE);
01404     return true;
01405 }
01406 
01407 struct channel *select_channel(char *channel)
01408 {
01409     struct channel *cp = (struct channel *)hashfindLEN(channel,
01410         strlen(channel), &mudstate.channel_htab);
01411     return cp;
01412 }
01413 
01414 struct comuser *select_user(struct channel *ch, dbref player)
01415 {
01416     if (!ch)
01417     {
01418         return NULL;
01419     }
01420 
01421     int first = 0;
01422     int last = ch->num_users - 1;
01423     int dir = 1;
01424     int current = 0;
01425 
01426     while (dir && (first <= last))
01427     {
01428         current = (first + last) / 2;
01429         if (ch->users[current] == NULL)
01430         {
01431             last--;
01432             continue;
01433         }
01434         if (ch->users[current]->who == player)
01435         {
01436             dir = 0;
01437         }
01438         else if (ch->users[current]->who < player)
01439         {
01440             dir = 1;
01441             first = current + 1;
01442         }
01443         else
01444         {
01445             dir = -1;
01446             last = current - 1;
01447         }
01448     }
01449 
01450     if (!dir)
01451     {
01452         return ch->users[current];
01453     }
01454     else
01455     {
01456         return NULL;
01457     }
01458 }
01459 
01460 #define MAX_ALIASES_PER_PLAYER 50
01461 
01462 void do_addcom
01463 (
01464     dbref executor,
01465     dbref caller,
01466     dbref enactor,
01467     int   key,
01468     int   nargs,
01469     char *arg1,
01470     char *arg2
01471 )
01472 {
01473     UNUSED_PARAMETER(caller);
01474     UNUSED_PARAMETER(enactor);
01475     UNUSED_PARAMETER(key);
01476     UNUSED_PARAMETER(nargs);
01477 
01478     if (!mudconf.have_comsys)
01479     {
01480         raw_notify(executor, "Comsys disabled.");
01481         return;
01482     }
01483     bool bValidAlias;
01484     int  nValidAlias;
01485     char *pValidAlias = MakeCanonicalComAlias(arg1, &nValidAlias, &bValidAlias);
01486     if (!bValidAlias)
01487     {
01488         raw_notify(executor, "You need to specify a valid alias.");
01489         return;
01490     }
01491     char *s = arg2;
01492     if (!*s)
01493     {
01494         raw_notify(executor, "You need to specify a channel.");
01495         return;
01496     }
01497     char channel[MAX_CHANNEL_LEN+1];
01498     char *t = channel;
01499     while (*s && ((t - channel) < MAX_CHANNEL_LEN))
01500     {
01501         if (*s != ' ')
01502             *t++ = *s++;
01503         else
01504             s++;
01505     }
01506     *t = '\0';
01507 
01508     int i, j, where;
01509     char *na;
01510     char **nc;
01511     struct channel *ch = select_channel(channel);
01512     char Buffer[MAX_CHANNEL_LEN+1];
01513     if (!ch)
01514     {
01515         int nVisualWidth;
01516         ANSI_TruncateToField(channel, sizeof(Buffer), Buffer, sizeof(Buffer), &nVisualWidth, ANSI_ENDGOAL_NORMAL);
01517         raw_notify(executor, tprintf("Channel %s does not exist yet.", Buffer));
01518         return;
01519     }
01520     if (!test_join_access(executor, ch))
01521     {
01522         raw_notify(executor, "Sorry, this channel type does not allow you to join.");
01523         return;
01524     }
01525     comsys_t *c = get_comsys(executor);
01526     if (c->numchannels >= MAX_ALIASES_PER_PLAYER)
01527     {
01528         raw_notify(executor, tprintf("Sorry, but you have reached the maximum number of aliases allowed."));
01529         return;
01530     }
01531     for (j = 0; j < c->numchannels && (strcmp(pValidAlias, c->alias + j * ALIAS_SIZE) > 0); j++)
01532     {
01533         ; // Nothing.
01534     }
01535     if (j < c->numchannels && !strcmp(pValidAlias, c->alias + j * ALIAS_SIZE))
01536     {
01537         char *p = tprintf("That alias is already in use for channel %s.", c->channels[j]);
01538         raw_notify(executor, p);
01539         return;
01540     }
01541     if (c->numchannels >= c->maxchannels)
01542     {
01543         c->maxchannels += 10;
01544 
01545         na = (char *)MEMALLOC(ALIAS_SIZE * c->maxchannels);
01546         ISOUTOFMEMORY(na);
01547         nc = (char **)MEMALLOC(sizeof(char *) * c->maxchannels);
01548         ISOUTOFMEMORY(nc);
01549 
01550         for (i = 0; i < c->numchannels; i++)
01551         {
01552             strcpy(na + i * ALIAS_SIZE, c->alias + i * ALIAS_SIZE);
01553             nc[i] = c->channels[i];
01554         }
01555         if (c->alias)
01556         {
01557             MEMFREE(c->alias);
01558             c->alias = NULL;
01559         }
01560         if (c->channels)
01561         {
01562             MEMFREE(c->channels);
01563             c->channels = NULL;
01564         }
01565         c->alias = na;
01566         c->channels = nc;
01567     }
01568     where = c->numchannels++;
01569     for (i = where; i > j; i--)
01570     {
01571         strcpy(c->alias + i * ALIAS_SIZE, c->alias + (i - 1) * ALIAS_SIZE);
01572         c->channels[i] = c->channels[i - 1];
01573     }
01574 
01575     where = j;
01576     memcpy(c->alias + where * ALIAS_SIZE, pValidAlias, nValidAlias);
01577     *(c->alias + where * ALIAS_SIZE + nValidAlias) = '\0';
01578     c->channels[where] = StringClone(channel);
01579 
01580     if (!select_user(ch, executor))
01581     {
01582         do_joinchannel(executor, ch);
01583     }
01584 
01585     raw_notify(executor, tprintf("Channel %s added with alias %s.", channel, pValidAlias));
01586 }
01587 
01588 void do_delcom(dbref executor, dbref caller, dbref enactor, int key, char *arg1)
01589 {
01590     UNUSED_PARAMETER(caller);
01591     UNUSED_PARAMETER(enactor);
01592     UNUSED_PARAMETER(key);
01593 
01594     if (!mudconf.have_comsys)
01595     {
01596         raw_notify(executor, "Comsys disabled.");
01597         return;
01598     }
01599     if (!arg1)
01600     {
01601         raw_notify(executor, "Need an alias to delete.");
01602         return;
01603     }
01604     comsys_t *c = get_comsys(executor);
01605     int i;
01606 
01607     for (i = 0; i < c->numchannels; i++)
01608     {
01609         if (!strcmp(arg1, c->alias + i * ALIAS_SIZE))
01610         {
01611             int itmp, found = 0;
01612             for (itmp = 0;itmp < c->numchannels; itmp++)
01613             {
01614                 if (!strcmp(c->channels[itmp],c->channels[i]))
01615                 {
01616                     found++;
01617                 }
01618             }
01619 
01620             // If we found no other channels, delete it
01621             //
01622             if (found <= 1)
01623             {
01624                 do_delcomchannel(executor, c->channels[i], false);
01625                 raw_notify(executor, tprintf("Alias %s for channel %s deleted.",
01626                     arg1, c->channels[i]));
01627                 MEMFREE(c->channels[i]);
01628             }
01629             else
01630             {
01631                 raw_notify(executor, tprintf("Alias %s for channel %s deleted.",
01632                     arg1, c->channels[i]));
01633             }
01634 
01635             c->channels[i] = NULL;
01636             c->numchannels--;
01637 
01638             for (; i < c->numchannels; i++)
01639             {
01640                 strcpy(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE);
01641                 c->channels[i] = c->channels[i + 1];
01642             }
01643             return;
01644         }
01645     }
01646     raw_notify(executor, "Unable to find that alias.");
01647 }
01648 
01649 void do_delcomchannel(dbref player, char *channel, bool bQuiet)
01650 {
01651     struct comuser *user;
01652 
01653     struct channel *ch = select_channel(channel);
01654     if (!ch)
01655     {
01656         raw_notify(player, tprintf("Unknown channel %s.", channel));
01657     }
01658     else
01659     {
01660         int i;
01661         int j = 0;
01662         for (i = 0; i < ch->num_users && !j; i++)
01663         {
01664             user = ch->users[i];
01665             if (user->who == player)
01666             {
01667                 do_comdisconnectchannel(player, channel);
01668                 if (!bQuiet)
01669                 {
01670                     if (  user->bUserIsOn
01671                        && !Hidden(player))
01672                     {
01673                         char *messNormal, *messNoComtitle;
01674                         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0,
01675                                             ch->header, user, ":has left this channel.",
01676                                             &messNormal, &messNoComtitle);
01677                         SendChannelMessage(player, ch, messNormal, messNoComtitle);
01678                     }
01679                     raw_notify(player, tprintf("You have left channel %s.", channel));
01680                 }
01681 
01682                 if (user->title)
01683                 {
01684                     MEMFREE(user->title);
01685                     user->title = NULL;
01686                 }
01687                 MEMFREE(user);
01688                 user = NULL;
01689                 j = 1;
01690             }
01691         }
01692 
01693         if (j)
01694         {
01695             ch->num_users--;
01696             for (i--; i < ch->num_users; i++)
01697             {
01698                 ch->users[i] = ch->users[i + 1];
01699             }
01700         }
01701     }
01702 }
01703 
01704 void do_createchannel(dbref executor, dbref caller, dbref enactor, int key, char *channel)
01705 {
01706     UNUSED_PARAMETER(caller);
01707     UNUSED_PARAMETER(enactor);
01708     UNUSED_PARAMETER(key);
01709 
01710     if (!*channel)
01711     {
01712         raw_notify(executor, "You must specify a channel to create.");
01713         return;
01714     }
01715     if (!Comm_All(executor))
01716     {
01717         raw_notify(executor, NOPERM_MESSAGE);
01718         return;
01719     }
01720     struct channel *newchannel = (struct channel *)MEMALLOC(sizeof(struct channel));
01721     ISOUTOFMEMORY(newchannel);
01722 
01723     int   vwChannel;
01724     size_t nNameNoANSI;
01725     char *pNameNoANSI;
01726     char Buffer[MAX_HEADER_LEN];
01727     int nChannel = ANSI_TruncateToField(channel, sizeof(Buffer),
01728         Buffer, sizeof(Buffer), &vwChannel, ANSI_ENDGOAL_NORMAL);
01729     if (nChannel == vwChannel)
01730     {
01731         // The channel name does not contain ANSI, so first, we add some to
01732         // get the header.
01733         //
01734         const int nMax = MAX_HEADER_LEN - (sizeof(ANSI_HILITE)-1)
01735                        - (sizeof(ANSI_NORMAL)-1) - 2;
01736         if (nChannel > nMax)
01737         {
01738             nChannel = nMax;
01739         }
01740         Buffer[nChannel] = '\0';
01741         sprintf(newchannel->header, "%s[%s]%s", ANSI_HILITE, Buffer,
01742             ANSI_NORMAL);
01743 
01744         // Then, we use the non-ANSI part for the name.
01745         //
01746         nNameNoANSI = nChannel;
01747         pNameNoANSI = Buffer;
01748     }
01749     else
01750     {
01751         // The given channel name does contain ANSI.
01752         //
01753         memcpy(newchannel->header, Buffer, nChannel+1);
01754         pNameNoANSI = strip_ansi(Buffer, &nNameNoANSI);
01755     }
01756     if (nNameNoANSI > MAX_CHANNEL_LEN)
01757     {
01758         nNameNoANSI = MAX_CHANNEL_LEN;
01759     }
01760     memcpy(newchannel->name, pNameNoANSI, nNameNoANSI);
01761     newchannel->name[nNameNoANSI] = '\0';
01762 
01763     if (select_channel(newchannel->name))
01764     {
01765         raw_notify(executor, tprintf("Channel %s already exists.", newchannel->name));
01766         MEMFREE(newchannel);
01767         return;
01768     }
01769 
01770     newchannel->type = 127;
01771     newchannel->temp1 = 0;
01772     newchannel->temp2 = 0;
01773     newchannel->charge = 0;
01774     newchannel->charge_who = executor;
01775     newchannel->amount_col = 0;
01776     newchannel->num_users = 0;
01777     newchannel->max_users = 0;
01778     newchannel->users = NULL;
01779     newchannel->on_users = NULL;
01780     newchannel->chan_obj = NOTHING;
01781     newchannel->num_messages = 0;
01782 
01783     num_channels++;
01784 
01785     hashaddLEN(newchannel->name, strlen(newchannel->name), newchannel, &mudstate.channel_htab);
01786 
01787     // Report the channel creation using non-ANSI name.
01788     //
01789     raw_notify(executor, tprintf("Channel %s created.", newchannel->name));
01790 }
01791 
01792 void do_destroychannel(dbref executor, dbref caller, dbref enactor, int key, char *channel)
01793 {
01794     UNUSED_PARAMETER(caller);
01795     UNUSED_PARAMETER(enactor);
01796     UNUSED_PARAMETER(key);
01797 
01798     struct channel *ch;
01799     int j;
01800 
01801     if (!mudconf.have_comsys)
01802     {
01803         raw_notify(executor, "Comsys disabled.");
01804         return;
01805     }
01806     ch = (struct channel *)hashfindLEN(channel, strlen(channel), &mudstate.channel_htab);
01807 
01808     if (!ch)
01809     {
01810         raw_notify(executor, tprintf("Could not find channel %s.", channel));
01811         return;
01812     }
01813     else if (  !Comm_All(executor)
01814             && !Controls(executor, ch->charge_who))
01815     {
01816         raw_notify(executor, NOPERM_MESSAGE);
01817         return;
01818     }
01819     num_channels--;
01820     hashdeleteLEN(channel, strlen(channel), &mudstate.channel_htab);
01821 
01822     for (j = 0; j < ch->num_users; j++)
01823     {
01824         MEMFREE(ch->users[j]);
01825         ch->users[j] = NULL;
01826     }
01827     MEMFREE(ch->users);
01828     ch->users = NULL;
01829     MEMFREE(ch);
01830     ch = NULL;
01831     raw_notify(executor, tprintf("Channel %s destroyed.", channel));
01832 }
01833 
01834 #if 0
01835 void do_cleanupchannels(void)
01836 {
01837     struct channel *ch;
01838     for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
01839          ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
01840     {
01841         struct comuser *user, *prevuser = NULL;
01842         for (user = ch->on_users; user; )
01843         {
01844             if (isPlayer(user->who))
01845             {
01846                 if (!test_join_access(user->who, ch))
01847                 //if (!Connected(user->who))
01848                 {
01849                     // Go looking for user in the array.
01850                     //
01851                     bool bFound = false;
01852                     int iPos;
01853                     for (iPos = 0; iPos < ch->num_users && !bFound; iPos++)
01854                     {
01855                         if (ch->users[iPos] == user)
01856                         {
01857                             bFound = true;
01858                         }
01859                     }
01860 
01861                     if (bFound)
01862                     {
01863                         // Remove user from the array.
01864                         //
01865                         ch->num_users--;
01866                         for (iPos--; iPos < ch->num_users; iPos++)
01867                         {
01868                             ch->users[iPos] = ch->users[iPos+1];
01869                         }
01870 
01871                         // Save user pointer for later reporting and freeing.
01872                         //
01873                         struct comuser *cuVictim = user;
01874 
01875                         // Unlink user from the list, and decide who to look at next.
01876                         //
01877                         if (prevuser)
01878                         {
01879                             prevuser->on_next = user->on_next;
01880                         }
01881                         else
01882                         {
01883                             ch->on_users = user->on_next;
01884                         }
01885                         user = user->on_next;
01886 
01887                         // Reporting
01888                         //
01889                         if (!Hidden(cuVictim->who))
01890                         {
01891                             char *mess = StartBuildChannelMessage(cuVictim->who,
01892                                 (ch->type & CHANNEL_SPOOF) != 0, ch->header, cuVictim->title,
01893                                 Moniker(cuVictim->who), ":is booted off the channel by the system.");
01894                             do_comsend(ch, mess);
01895                             EndBuildChannelMessage(mess);
01896                         }
01897                         raw_notify(cuVictim->who, tprintf("The system has booted you off channel %s.", ch->name));
01898 
01899                         // Freeing
01900                         //
01901                         if (cuVictim->title)
01902                         {
01903                             MEMFREE(cuVictim->title);
01904                             cuVictim->title = NULL;
01905                         }
01906                         MEMFREE(cuVictim);
01907                         cuVictim = NULL;
01908 
01909                         continue;
01910                     }
01911                 }
01912             }
01913 
01914             prevuser = user;
01915             user = user->on_next;
01916         }
01917     }
01918 }
01919 #endif
01920 
01921 static void do_listchannels(dbref player)
01922 {
01923     struct channel *ch;
01924     char temp[LBUF_SIZE];
01925 
01926     bool perm = Comm_All(player);
01927     if (!perm)
01928     {
01929         raw_notify(player, "Warning: Only public channels and your channels will be shown.");
01930     }
01931     raw_notify(player, "*** Channel      --Flags--  Obj   Own   Charge  Balance  Users   Messages");
01932 
01933     for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
01934          ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
01935     {
01936         if (  perm
01937            || (ch->type & CHANNEL_PUBLIC)
01938            || Controls(player, ch->charge_who))
01939         {
01940             sprintf(temp, "%c%c%c %-13.13s %c%c%c/%c%c%c %5d %5d %8d %8d %6d %10d",
01941                 (ch->type & CHANNEL_PUBLIC) ? 'P' : '-',
01942                 (ch->type & CHANNEL_LOUD) ? 'L' : '-',
01943                 (ch->type & CHANNEL_SPOOF) ? 'S' : '-',
01944                 ch->name,
01945                 (ch->type & CHANNEL_PLAYER_JOIN) ? 'J' : '-',
01946                 (ch->type & CHANNEL_PLAYER_TRANSMIT) ? 'X' : '-',
01947                 (ch->type & CHANNEL_PLAYER_RECEIVE) ? 'R' : '-',
01948                 (ch->type & CHANNEL_OBJECT_JOIN) ? 'j' : '-',
01949                 (ch->type & CHANNEL_OBJECT_TRANSMIT) ? 'x' : '-',
01950                 (ch->type & CHANNEL_OBJECT_RECEIVE) ? 'r' : '-',
01951                 (ch->chan_obj != NOTHING) ? ch->chan_obj : -1,
01952                 ch->charge_who, ch->charge, ch->amount_col, ch->num_users, ch->num_messages);
01953             raw_notify(player, temp);
01954         }
01955     }
01956     raw_notify(player, "-- End of list of Channels --");
01957 }
01958 
01959 void do_comtitle
01960 (
01961     dbref executor,
01962     dbref caller,
01963     dbref enactor,
01964     int   key,
01965     int   nargs,
01966     char *arg1,
01967     char *arg2
01968 )
01969 {
01970     UNUSED_PARAMETER(caller);
01971     UNUSED_PARAMETER(enactor);
01972     UNUSED_PARAMETER(nargs);
01973 
01974     if (!mudconf.have_comsys)
01975     {
01976         raw_notify(executor, "Comsys disabled.");
01977         return;
01978     }
01979     if (!*arg1)
01980     {
01981         raw_notify(executor, "Need an alias to do comtitle.");
01982         return;
01983     }
01984 
01985     char channel[MAX_CHANNEL_LEN+1];
01986     strcpy(channel, get_channel_from_alias(executor, arg1));
01987 
01988     if (channel[0] == '\0')
01989     {
01990         raw_notify(executor, "Unknown alias.");
01991         return;
01992     }
01993     struct channel *ch = select_channel(channel);
01994     if (ch)
01995     {
01996         if (select_user(ch, executor))
01997         {
01998             if (key == COMTITLE_OFF)
01999             {
02000                 if ((ch->type & CHANNEL_SPOOF) == 0)
02001                 {
02002                     raw_notify(executor, tprintf("Comtitles are now off for channel %s", channel));
02003                     do_setcomtitlestatus(executor, ch, false);
02004                 }
02005                 else
02006                 {
02007                     raw_notify(executor, "You can not turn off comtitles on that channel.");
02008                 }
02009             }
02010             else if (key == COMTITLE_ON)
02011             {
02012                 raw_notify(executor, tprintf("Comtitles are now on for channel %s", channel));
02013                 do_setcomtitlestatus(executor, ch, true);
02014             }
02015             else
02016             {
02017                 char *pValidatedTitleValue = RestrictTitleValue(arg2);
02018                 do_setnewtitle(executor, ch, pValidatedTitleValue);
02019                 raw_notify(executor, tprintf("Title set to '%s' on channel %s.",
02020                     pValidatedTitleValue, channel));
02021             }
02022         }
02023     }
02024     else
02025     {
02026         raw_notify(executor, "Illegal comsys alias, please delete.");
02027     }
02028 }
02029 
02030 void do_comlist
02031 (
02032     dbref executor,
02033     dbref caller,
02034     dbref enactor,
02035     int key,
02036     char* pattern
02037 )
02038 {
02039     UNUSED_PARAMETER(caller);
02040     UNUSED_PARAMETER(enactor);
02041     UNUSED_PARAMETER(key);
02042 
02043     if (!mudconf.have_comsys)
02044     {
02045         raw_notify(executor, "Comsys disabled.");
02046         return;
02047     }
02048 
02049     bool bWild;
02050     if (  NULL != pattern
02051        && '\0' != *pattern)
02052     {
02053         bWild = true;
02054     }
02055     else
02056     {
02057         bWild = false;
02058     }
02059 
02060     raw_notify(executor, "Alias     Channel            Status   Title");
02061 
02062     comsys_t *c = get_comsys(executor);
02063     int i;
02064     for (i = 0; i < c->numchannels; i++)
02065     {
02066         struct comuser *user = select_user(select_channel(c->channels[i]), executor);
02067         if (user)
02068         {
02069             if (  !bWild
02070                || quick_wild(pattern,c->channels[i]))
02071             {
02072                 char *p =
02073                     tprintf("%-9.9s %-18.18s %s %s %s",
02074                         c->alias + i * ALIAS_SIZE,
02075                         c->channels[i],
02076                         (user->bUserIsOn ? "on " : "off"),
02077                         (user->ComTitleStatus ? "con " : "coff"),
02078                         user->title);
02079                 raw_notify(executor, p);
02080             }
02081         }
02082         else
02083         {
02084             raw_notify(executor, tprintf("Bad Comsys Alias: %s for Channel: %s", c->alias + i * ALIAS_SIZE, c->channels[i]));
02085         }
02086     }
02087     raw_notify(executor, "-- End of comlist --");
02088 }
02089 
02090 void do_channelnuke(dbref player)
02091 {
02092     struct channel *ch;
02093     int j;
02094 
02095     for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
02096          ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
02097     {
02098         if (player == ch->charge_who)
02099         {
02100             num_channels--;
02101             hashdeleteLEN(ch->name, strlen(ch->name), &mudstate.channel_htab);
02102 
02103             for (j = 0; j < ch->num_users; j++)
02104             {
02105                 MEMFREE(ch->users[j]);
02106                 ch->users[j] = NULL;
02107             }
02108             MEMFREE(ch->users);
02109             ch->users = NULL;
02110             MEMFREE(ch);
02111             ch = NULL;
02112         }
02113     }
02114 }
02115 
02116 void do_clearcom(dbref executor, dbref caller, dbref enactor, int unused2)
02117 {
02118     UNUSED_PARAMETER(unused2);
02119 
02120     if (!mudconf.have_comsys)
02121     {
02122         raw_notify(executor, "Comsys disabled.");
02123         return;
02124     }
02125     comsys_t *c = get_comsys(executor);
02126 
02127     int i;
02128     for (i = (c->numchannels) - 1; i > -1; --i)
02129     {
02130         do_delcom(executor, caller, enactor, 0, c->alias + i * ALIAS_SIZE);
02131     }
02132 }
02133 
02134 void do_allcom(dbref executor, dbref caller, dbref enactor, int key, char *arg1)
02135 {
02136     UNUSED_PARAMETER(caller);
02137     UNUSED_PARAMETER(enactor);
02138     UNUSED_PARAMETER(key);
02139 
02140     if (!mudconf.have_comsys)
02141     {
02142         raw_notify(executor, "Comsys disabled.");
02143         return;
02144     }
02145     if (  strcmp(arg1, "who") != 0
02146        && strcmp(arg1, "on")  != 0
02147        && strcmp(arg1, "off") != 0)
02148     {
02149         raw_notify(executor, "Only options available are: on, off and who.");
02150         return;
02151     }
02152 
02153     comsys_t *c = get_comsys(executor);
02154     int i;
02155     for (i = 0; i < c->numchannels; i++)
02156     {
02157         do_processcom(executor, c->channels[i], arg1);
02158         if (strcmp(arg1, "who") == 0)
02159         {
02160             raw_notify(executor, "");
02161         }
02162     }
02163 }
02164 
02165 void sort_users(struct channel *ch)
02166 {
02167     int i;
02168     bool done = false;
02169     struct comuser *user;
02170     int nu = ch->num_users;
02171 
02172     while (!done)
02173     {
02174         done = true;
02175         for (i = 0; i < (nu - 1); i++)
02176         {
02177             if (ch->users[i]->who > ch->users[i + 1]->who)
02178             {
02179                 user = ch->users[i];
02180                 ch->users[i] = ch->users[i + 1];
02181                 ch->users[i + 1] = user;
02182                 done = false;
02183             }
02184         }
02185     }
02186 }
02187 
02188 void do_channelwho(dbref executor, dbref caller, dbref enactor, int key, char *arg1)
02189 {
02190     UNUSED_PARAMETER(caller);
02191     UNUSED_PARAMETER(enactor);
02192     UNUSED_PARAMETER(key);
02193 
02194     if (!mudconf.have_comsys)
02195     {
02196         raw_notify(executor, "Comsys disabled.");
02197         return;
02198     }
02199 
02200     char channel[MAX_CHANNEL_LEN+1];
02201     char *s = arg1;
02202     char *t = channel;
02203     while (*s && *s != '/' && ((t - channel) < MAX_CHANNEL_LEN))
02204     {
02205         *t++ = *s++;
02206     }
02207     *t = 0;
02208 
02209     bool flag = false;
02210     if (*s && *(s + 1))
02211     {
02212         flag = (*(s + 1) == 'a');
02213     }
02214 
02215     struct channel *ch = select_channel(channel);
02216     if (!ch)
02217     {
02218         raw_notify(executor, tprintf("Unknown channel %s.", channel));
02219         return;
02220     }
02221     if ( !(  Comm_All(executor)
02222           || Controls(executor,ch->charge_who)))
02223     {
02224         raw_notify(executor, NOPERM_MESSAGE);
02225         return;
02226     }
02227     raw_notify(executor, tprintf("-- %s --", ch->name));
02228     raw_notify(executor, tprintf("%-29.29s %-6.6s %-6.6s", "Name", "Status", "Player"));
02229     struct comuser *user;
02230     char *buff;
02231     char temp[LBUF_SIZE];
02232     int i;
02233     for (i = 0; i < ch->num_users; i++)
02234     {
02235         user = ch->users[i];
02236         if (  (  flag
02237               || UNDEAD(user->who))
02238            && (  !Hidden(user->who)
02239               || Wizard_Who(executor)
02240               || See_Hidden(executor)))
02241         {
02242             buff = unparse_object(executor, user->who, false);
02243             sprintf(temp, "%-29.29s %-6.6s %-6.6s", strip_ansi(buff),
02244                 user->bUserIsOn ? "on " : "off",
02245                 isPlayer(user->who) ? "yes" : "no ");
02246             raw_notify(executor, temp);
02247             free_lbuf(buff);
02248         }
02249     }
02250     raw_notify(executor, tprintf("-- %s --", ch->name));
02251 }
02252 
02253 static void do_comdisconnectraw_notify(dbref player, char *chan)
02254 {
02255     struct channel *ch = select_channel(chan);
02256     if (!ch) return;
02257 
02258     struct comuser *cu = select_user(ch, player);
02259     if (!cu) return;
02260 
02261     if (  (ch->type & CHANNEL_LOUD)
02262        && cu->bUserIsOn
02263        && !Hidden(player))
02264     {
02265         char *messNormal, *messNoComtitle;
02266         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, cu,
02267             ":has disconnected.", &messNormal, &messNoComtitle);
02268         SendChannelMessage(player, ch, messNormal, messNoComtitle);
02269     }
02270 }
02271 
02272 static void do_comconnectraw_notify(dbref player, char *chan)
02273 {
02274     struct channel *ch = select_channel(chan);
02275     if (!ch) return;
02276     struct comuser *cu = select_user(ch, player);
02277     if (!cu) return;
02278 
02279     if (  (ch->type & CHANNEL_LOUD)
02280        && cu->bUserIsOn
02281        && !Hidden(player))
02282     {
02283         char *messNormal, *messNoComtitle;
02284         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, cu,
02285             ":has connected.", &messNormal, &messNoComtitle);
02286         SendChannelMessage(player, ch, messNormal, messNoComtitle);
02287     }
02288 }
02289 
02290 static void do_comconnectchannel(dbref player, char *channel, char *alias, int i)
02291 {
02292     struct comuser *user;
02293 
02294     struct channel *ch = select_channel(channel);
02295     if (ch)
02296     {
02297         for (user = ch->on_users;
02298         user && user->who != player;
02299         user = user->on_next) ;
02300 
02301         if (!user)
02302         {
02303             user = select_user(ch, player);
02304             if (user)
02305             {
02306                 user->on_next = ch->on_users;
02307                 ch->on_users = user;
02308             }
02309             else
02310             {
02311                 raw_notify(player, tprintf("Bad Comsys Alias: %s for Channel: %s", alias + i * ALIAS_SIZE, channel));
02312             }
02313         }
02314     }
02315     else
02316     {
02317         raw_notify(player, tprintf("Bad Comsys Alias: %s for Channel: %s", alias + i * ALIAS_SIZE, channel));
02318     }
02319 }
02320 
02321 void do_comdisconnect(dbref player)
02322 {
02323     comsys_t *c = get_comsys(player);
02324     int i;
02325 
02326     for (i = 0; i < c->numchannels; i++)
02327     {
02328         char *CurrentChannel = c->channels[i];
02329         bool bFound = false;
02330         int j;
02331 
02332         for (j = 0; j < i; j++)
02333         {
02334             if (strcmp(c->channels[j], CurrentChannel) == 0)
02335             {
02336                 bFound = true;
02337                 break;
02338             }
02339         }
02340 
02341         if (!bFound)
02342         {
02343             do_comdisconnectchannel(player, CurrentChannel);
02344             do_comdisconnectraw_notify(player, CurrentChannel);
02345         }
02346     }
02347 }
02348 
02349 void do_comconnect(dbref player)
02350 {
02351     comsys_t *c = get_comsys(player);
02352     int i;
02353 
02354     for (i = 0; i < c->numchannels; i++)
02355     {
02356         char *CurrentChannel = c->channels[i];
02357         bool bFound = false;
02358         int j;
02359 
02360         for (j = 0; j < i; j++)
02361         {
02362             if (strcmp(c->channels[j], CurrentChannel) == 0)
02363             {
02364                 bFound = true;
02365                 break;
02366             }
02367         }
02368 
02369         if (!bFound)
02370         {
02371             do_comconnectchannel(player, CurrentChannel, c->alias, i);
02372             do_comconnectraw_notify(player, CurrentChannel);
02373         }
02374     }
02375 }
02376 
02377 
02378 void do_comdisconnectchannel(dbref player, char *channel)
02379 {
02380     struct channel *ch = select_channel(channel);
02381     if (!ch)
02382     {
02383         return;
02384     }
02385 
02386     struct comuser *prevuser = NULL;
02387     struct comuser *user;
02388     for (user = ch->on_users; user;)
02389     {
02390         if (user->who == player)
02391         {
02392             if (prevuser)
02393             {
02394                 prevuser->on_next = user->on_next;
02395             }
02396             else
02397             {
02398                 ch->on_users = user->on_next;
02399             }
02400             return;
02401         }
02402         else
02403         {
02404             prevuser = user;
02405             user = user->on_next;
02406         }
02407     }
02408 }
02409 
02410 void do_editchannel
02411 (
02412     dbref executor,
02413     dbref caller,
02414     dbref enactor,
02415     int   flag,
02416     int   nargs,
02417     char *arg1,
02418     char *arg2
02419 )
02420 {
02421     UNUSED_PARAMETER(caller);
02422     UNUSED_PARAMETER(enactor);
02423     UNUSED_PARAMETER(nargs);
02424 
02425     if (!mudconf.have_comsys)
02426     {
02427         raw_notify(executor, "Comsys disabled.");
02428         return;
02429     }
02430     struct channel *ch = select_channel(arg1);
02431     if (!ch)
02432     {
02433         raw_notify(executor, tprintf("Unknown channel %s.", arg1));
02434         return;
02435     }
02436     if ( !(  Comm_All(executor)
02437           || Controls(executor, ch->charge_who)))
02438     {
02439         raw_notify(executor, NOPERM_MESSAGE);
02440         return;
02441     }
02442 
02443     bool add_remove = true;
02444     char *s = arg2;
02445     if (*s == '!')
02446     {
02447         add_remove = false;
02448         s++;
02449     }
02450     switch (flag)
02451     {
02452     case 0:
02453         {
02454             dbref who = lookup_player(executor, arg2, true);
02455             if (NOTHING == who)
02456             {
02457                 raw_notify(executor, "Invalid player.");
02458             }
02459             else
02460             {
02461                 ch->charge_who = who;
02462                 raw_notify(executor, "Set.");
02463             }
02464         }
02465         break;
02466 
02467     case 1:
02468         ch->charge = mux_atol(arg2);
02469         raw_notify(executor, "Set.");
02470         break;
02471 
02472     case 3:
02473         {
02474             int access = 0;
02475             if (strcmp(s, "join") == 0)
02476             {
02477                 access = CHANNEL_PLAYER_JOIN;
02478             }
02479             else if (strcmp(s, "receive") == 0)
02480             {
02481                 access = CHANNEL_PLAYER_RECEIVE;
02482             }
02483             else if (strcmp(s, "transmit") == 0)
02484             {
02485                 access = CHANNEL_PLAYER_TRANSMIT;
02486             }
02487             else
02488             {
02489                 raw_notify(executor, "@cpflags: Unknown Flag.");
02490             }
02491 
02492             if (access)
02493             {
02494                 if (add_remove)
02495                 {
02496                     ch->type |= access;
02497                     raw_notify(executor, "@cpflags: Set.");
02498                 }
02499                 else
02500                 {
02501                     ch->type &= ~access;
02502                     raw_notify(executor, "@cpflags: Cleared.");
02503                 }
02504             }
02505         }
02506         break;
02507 
02508     case 4:
02509         {
02510             int access = 0;
02511             if (strcmp(s, "join") == 0)
02512             {
02513                 access = CHANNEL_OBJECT_JOIN;
02514             }
02515             else if (strcmp(s, "receive") == 0)
02516             {
02517                 access = CHANNEL_OBJECT_RECEIVE;
02518             }
02519             else if (strcmp(s, "transmit") == 0)
02520             {
02521                 access = CHANNEL_OBJECT_TRANSMIT;
02522             }
02523             else
02524             {
02525                 raw_notify(executor, "@coflags: Unknown Flag.");
02526             }
02527 
02528             if (access)
02529             {
02530                 if (add_remove)
02531                 {
02532                     ch->type |= access;
02533                     raw_notify(executor, "@coflags: Set.");
02534                 }
02535                 else
02536                 {
02537                     ch->type &= ~access;
02538                     raw_notify(executor, "@coflags: Cleared.");
02539                 }
02540             }
02541         }
02542         break;
02543     }
02544 }
02545 
02546 bool test_join_access(dbref player, struct channel *chan)
02547 {
02548     if (Comm_All(player))
02549     {
02550         return true;
02551     }
02552 
02553     int access;
02554     if (isPlayer(player))
02555     {
02556         access = CHANNEL_PLAYER_JOIN;
02557     }
02558     else
02559     {
02560         access = CHANNEL_OBJECT_JOIN;
02561     }
02562     return (  (chan->type & access) != 0
02563            || could_doit(player, chan->chan_obj, A_LOCK));
02564 }
02565 
02566 bool test_transmit_access(dbref player, struct channel *chan)
02567 {
02568     if (Comm_All(player))
02569     {
02570         return true;
02571     }
02572 
02573     int access;
02574     if (isPlayer(player))
02575     {
02576         access = CHANNEL_PLAYER_TRANSMIT;
02577     }
02578     else
02579     {
02580         access = CHANNEL_OBJECT_TRANSMIT;
02581     }
02582     return (  (chan->type & access) != 0
02583            || could_doit(player, chan->chan_obj, A_LUSE));
02584 
02585 }
02586 
02587 bool test_receive_access(dbref player, struct channel *chan)
02588 {
02589     if (Comm_All(player))
02590     {
02591         return true;
02592     }
02593 
02594     int access;
02595     if (isPlayer(player))
02596     {
02597         access = CHANNEL_PLAYER_RECEIVE;
02598     }
02599     else
02600     {
02601         access = CHANNEL_OBJECT_RECEIVE;
02602     }
02603     return (  (chan->type & access) != 0
02604            || could_doit(player, chan->chan_obj, A_LENTER));
02605 
02606 }
02607 
02608 // true means continue, false means stop
02609 //
02610 bool do_comsystem(dbref who, char *cmd)
02611 {
02612     char *t;
02613     char *alias = alloc_lbuf("do_comsystem");
02614     char *s = alias;
02615     for (t = cmd; *t && *t != ' ' && s < alias + LBUF_SIZE; *s++ = *t++)
02616     {
02617         ; // Nothing.
02618     }
02619 
02620     *s = '\0';
02621 
02622     if (*t)
02623     {
02624         t++;
02625     }
02626 
02627     char *ch = get_channel_from_alias(who, alias);
02628     if (  ch[0] != '\0'
02629        && t[0] != '\0')
02630     {
02631         do_processcom(who, ch, t);
02632         free_lbuf(alias);
02633         return false;
02634     }
02635     else
02636     {
02637         free_lbuf(alias);
02638     }
02639     return true;
02640 }
02641 
02642 void do_cemit
02643 (
02644     dbref executor,
02645     dbref caller,
02646     dbref enactor,
02647     int   key,
02648     int   nargs,
02649     char *chan,
02650     char *text
02651 )
02652 {
02653     UNUSED_PARAMETER(caller);
02654     UNUSED_PARAMETER(enactor);
02655     UNUSED_PARAMETER(nargs);
02656 
02657     if (!mudconf.have_comsys)
02658     {
02659         raw_notify(executor, "Comsys disabled.");
02660         return;
02661     }
02662     struct channel *ch = select_channel(chan);
02663     if (!ch)
02664     {
02665         raw_notify(executor, tprintf("Channel %s does not exist.", chan));
02666         return;
02667     }
02668     if (  !Controls(executor, ch->charge_who)
02669        && !Comm_All(executor))
02670     {
02671         raw_notify(executor, NOPERM_MESSAGE);
02672         return;
02673     }
02674     char *text2 = alloc_lbuf("do_cemit");
02675     if (key == CEMIT_NOHEADER)
02676     {
02677         strcpy(text2, text);
02678     }
02679     else
02680     {
02681         strcpy(text2, tprintf("%s %s", ch->header, text));
02682     }
02683     SendChannelMessage(executor, ch, text2, text2);
02684 }
02685 
02686 void do_chopen
02687 (
02688     dbref executor,
02689     dbref caller,
02690     dbref enactor,
02691     int   key,
02692     int   nargs,
02693     char *chan,
02694     char *value
02695 )
02696 {
02697     UNUSED_PARAMETER(nargs);
02698 
02699     if (!mudconf.have_comsys)
02700     {
02701         raw_notify(executor, "Comsys disabled.");
02702         return;
02703     }
02704     if (key == CSET_LIST)
02705     {
02706         do_chanlist(executor, caller, enactor, 1, NULL);
02707         return;
02708     }
02709 
02710     char *msg = NULL;
02711     struct channel *ch = select_channel(chan);
02712     if (!ch)
02713     {
02714         msg = tprintf("@cset: Channel %s does not exist.", chan);
02715         raw_notify(executor, msg);
02716         return;
02717     }
02718     if (  !Controls(executor, ch->charge_who)
02719        && !Comm_All(executor))
02720     {
02721         raw_notify(executor, NOPERM_MESSAGE);
02722         return;
02723     }
02724     char *buff;
02725     dbref thing;
02726 
02727     switch (key)
02728     {
02729     case CSET_PUBLIC:
02730         ch->type |= CHANNEL_PUBLIC;
02731         msg = tprintf("@cset: Channel %s placed on the public listings.", chan);
02732         break;
02733 
02734     case CSET_PRIVATE:
02735         ch->type &= ~CHANNEL_PUBLIC;
02736         msg = tprintf("@cset: Channel %s taken off the public listings." ,chan);
02737         break;
02738 
02739     case CSET_LOUD:
02740         ch->type |= CHANNEL_LOUD;
02741         msg = tprintf("@cset: Channel %s now sends connect/disconnect msgs.", chan);
02742         break;
02743 
02744     case CSET_QUIET:
02745         ch->type &= ~CHANNEL_LOUD;
02746         msg = tprintf("@cset: Channel %s connect/disconnect msgs muted.", chan);
02747         break;
02748 
02749     case CSET_SPOOF:
02750         ch->type |= CHANNEL_SPOOF;
02751         msg = tprintf("@cset: Channel %s set spoofable.", chan);
02752         break;
02753 
02754     case CSET_NOSPOOF:
02755         ch->type &= ~CHANNEL_SPOOF;
02756         msg = tprintf("@cset: Channel %s set unspoofable.", chan);
02757         break;
02758 
02759     case CSET_OBJECT:
02760         init_match(executor, value, NOTYPE);
02761         match_everything(0);
02762         thing = match_result();
02763 
02764         if (thing == NOTHING)
02765         {
02766             ch->chan_obj = thing;
02767             msg = tprintf("Channel %s is now disassociated from any channel object.", ch->name);
02768         }
02769         else if (Good_obj(thing))
02770         {
02771             ch->chan_obj = thing;
02772             buff = unparse_object(executor, thing, false);
02773             msg = tprintf("Channel %s is now using %s as channel object.", ch->name, buff);
02774             free_lbuf(buff);
02775         }
02776         else
02777         {
02778             msg = tprintf("%d is not a valid channel object.", thing);
02779         }
02780         break;
02781 
02782     case CSET_HEADER:
02783         do_cheader(executor, chan, value);
02784         msg = "Set.";
02785         break;
02786 
02787     case CSET_LOG:
02788         if (do_chanlog(executor, chan, value))
02789         {
02790             msg = tprintf("@cset: Channel %s maximum history set.", chan);
02791         }
02792         else
02793         {
02794             msg = tprintf("@cset: Maximum history must be a number less than or equal to %d.", MAX_RECALL_REQUEST);
02795         }
02796         break;
02797     }
02798     raw_notify(executor, msg);
02799 }
02800 
02801 void do_chboot
02802 (
02803     dbref executor,
02804     dbref caller,
02805     dbref enactor,
02806     int   key,
02807     int   nargs,
02808     char *channel,
02809     char *victim
02810 )
02811 {
02812     UNUSED_PARAMETER(caller);
02813     UNUSED_PARAMETER(enactor);
02814     UNUSED_PARAMETER(nargs);
02815 
02816     // I sure hope it's not going to be that long.
02817     //
02818     if (!mudconf.have_comsys)
02819     {
02820         raw_notify(executor, "Comsys disabled.");
02821         return;
02822     }
02823     struct channel *ch = select_channel(channel);
02824     if (!ch)
02825     {
02826         raw_notify(executor, "@cboot: Unknown channel.");
02827         return;
02828     }
02829     struct comuser *user = select_user(ch, executor);
02830     if (!user)
02831     {
02832         raw_notify(executor, "@cboot: You are not on that channel.");
02833         return;
02834     }
02835     if (  !Controls(executor, ch->charge_who)
02836        && !Comm_All(executor))
02837     {
02838         raw_notify(executor, "@cboot: You can't do that!");
02839         return;
02840     }
02841     dbref thing = match_thing(executor, victim);
02842 
02843     if (!Good_obj(thing))
02844     {
02845         return;
02846     }
02847     struct comuser *vu = select_user(ch, thing);
02848     if (!vu)
02849     {
02850         raw_notify(executor, tprintf("@cboot: %s is not on the channel.",
02851             Moniker(thing)));
02852         return;
02853     }
02854 
02855     raw_notify(executor, tprintf("You boot %s off channel %s.",
02856                                  Moniker(thing), ch->name));
02857     raw_notify(thing, tprintf("%s boots you off channel %s.",
02858                               Moniker(thing), ch->name));
02859 
02860     if (!(key & CBOOT_QUIET))
02861     {
02862         char *mess1, *mess1nct;
02863         char *mess2, *mess2nct;
02864         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user,
02865                             ":boots", &mess1, &mess1nct);
02866         BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, 0, vu,
02867                             ":off the channel.", &mess2, &mess2nct);
02868         char *messNormal = alloc_lbuf("do_chboot.messnormal");
02869         char *messNoComtitle = alloc_lbuf("do_chboot.messnocomtitle");
02870         char *mnp = messNormal;
02871         char *mnctp = messNoComtitle;
02872         if (mess1)
02873         {
02874             safe_str(mess1, messNormal, &mnp);
02875             free_lbuf(mess1);
02876         }
02877         if (mess2)
02878         {
02879             safe_str(mess2, messNormal, &mnp);
02880             free_lbuf(mess2);
02881         }
02882         *mnp = '\0';
02883         if (mess1nct)
02884         {
02885             safe_str(mess1nct, messNoComtitle, &mnctp);
02886             free_lbuf(mess1nct);
02887         }
02888         if (mess2nct)
02889         {
02890             safe_str(mess2nct, messNoComtitle, &mnctp);
02891             free_lbuf(mess2nct);
02892         }
02893         *mnctp = '\0';
02894         SendChannelMessage(executor, ch, messNormal, messNoComtitle);
02895         do_delcomchannel(thing, channel, false);
02896     }
02897     else
02898     {
02899         do_delcomchannel(thing, channel, true);
02900     }
02901 }
02902 
02903 void do_cheader(dbref player, char *channel, char *header)
02904 {
02905     struct channel *ch = select_channel(channel);
02906     if (!ch)
02907     {
02908         raw_notify(player, "That channel does not exist.");
02909         return;
02910     }
02911     if (  !Controls(player, ch->charge_who)
02912        && !Comm_All(player))
02913     {
02914         raw_notify(player, NOPERM_MESSAGE);
02915         return;
02916     }
02917     char *p = RemoveSetOfCharacters(header, "\r\n\t");
02918 
02919     // Optimize/terminate any ANSI in the string.
02920     //
02921     char NewHeader_ANSI[MAX_HEADER_LEN+1];
02922     int nVisualWidth;
02923     int nLen = ANSI_TruncateToField(p, sizeof(NewHeader_ANSI),
02924         NewHeader_ANSI, sizeof(NewHeader_ANSI), &nVisualWidth,
02925         ANSI_ENDGOAL_NORMAL);
02926     memcpy(ch->header, NewHeader_ANSI, nLen+1);
02927 }
02928 
02929 struct chanlist_node
02930 {
02931     char *           name;
02932     struct channel * ptr;
02933 };
02934 
02935 static int DCL_CDECL chanlist_comp(const void* a, const void* b)
02936 {
02937     chanlist_node* ca = (chanlist_node*)a;
02938     chanlist_node* cb = (chanlist_node*)b;
02939     return mux_stricmp(ca->name, cb->name);
02940 }
02941 
02942 void do_chanlist
02943 (
02944     dbref executor,
02945     dbref caller,
02946     dbref enactor,
02947     int   key,
02948     char *pattern
02949 )
02950 {
02951     UNUSED_PARAMETER(caller);
02952     UNUSED_PARAMETER(enactor);
02953 
02954     if (!mudconf.have_comsys)
02955     {
02956         raw_notify(executor, "Comsys disabled.");
02957         return;
02958     }
02959     if (key & CLIST_FULL)
02960     {
02961         do_listchannels(executor);
02962         return;
02963     }
02964 
02965     dbref owner;
02966     struct channel *ch;
02967     int flags = 0;
02968     char *atrstr;
02969     char *temp = alloc_mbuf("do_chanlist_temp");
02970     char *buf = alloc_mbuf("do_chanlist_buf");
02971 
02972     if (key & CLIST_HEADERS)
02973     {
02974         raw_notify(executor, "*** Channel       Owner           Header");
02975     }
02976     else
02977     {
02978         raw_notify(executor, "*** Channel       Owner           Description");
02979     }
02980 
02981     bool bWild;
02982     if (  NULL != pattern
02983        && '\0' != *pattern)
02984     {
02985         bWild = true;
02986     }
02987     else
02988     {
02989         bWild = false;
02990     }
02991 
02992 #define MAX_SUPPORTED_NUM_ENTRIES 10000
02993 
02994     INT64 iEntryCount64 = mudstate.channel_htab.GetEntryCount();
02995     if (MAX_SUPPORTED_NUM_ENTRIES < iEntryCount64)
02996     {
02997         // Nobody should have so many channels.
02998         //
02999         iEntryCount64 = MAX_SUPPORTED_NUM_ENTRIES;
03000     }
03001     size_t entries = (size_t)iEntryCount64;
03002 
03003     struct chanlist_node* charray = (chanlist_node*)MEMALLOC(sizeof(chanlist_node)*entries);
03004     ISOUTOFMEMORY(charray);
03005 
03006     // Arrayify all the channels
03007     //
03008     size_t  actualEntries;
03009     for (  actualEntries = 0, ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
03010            ch
03011         && actualEntries < entries;
03012            ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
03013     {
03014             if (  !bWild
03015                || quick_wild(pattern, ch->name))
03016             {
03017                 charray[actualEntries].name = ch->name;
03018                 charray[actualEntries].ptr = ch;
03019                 actualEntries++;
03020             }
03021     }
03022 
03023     qsort(charray, actualEntries, sizeof(struct chanlist_node), chanlist_comp);
03024 
03025     for (size_t i = 0; i < actualEntries; i++)
03026     {
03027         ch = charray[i].ptr;
03028         if (  Comm_All(executor)
03029            || (ch->type & CHANNEL_PUBLIC)
03030            || Controls(executor, ch->charge_who))
03031         {
03032             char *pBuffer;
03033             if (key & CLIST_HEADERS)
03034             {
03035                 pBuffer = ch->header;
03036             }
03037             else
03038             {
03039                 atrstr = atr_pget(ch->chan_obj, A_DESC, &owner, &flags);
03040                 if (  NOTHING == ch->chan_obj
03041                    || !*atrstr)
03042                 {
03043                     strcpy(buf, "No description.");
03044                 }
03045                 else
03046                 {
03047                     sprintf(buf, "%-54.54s", atrstr);
03048                 }
03049                 free_lbuf(atrstr);
03050 
03051                 pBuffer = buf;
03052             }
03053 
03054             char *ownername_ansi = ANSI_TruncateAndPad_sbuf(Moniker(ch->charge_who), 15);
03055             sprintf(temp, "%c%c%c %-13.13s %s %-45.45s",
03056                 (ch->type & (CHANNEL_PUBLIC)) ? 'P' : '-',
03057                 (ch->type & (CHANNEL_LOUD)) ? 'L' : '-',
03058                 (ch->type & (CHANNEL_SPOOF)) ? 'S' : '-',
03059                 ch->name, ownername_ansi, pBuffer);
03060             free_sbuf(ownername_ansi);
03061 
03062             raw_notify(executor, temp);
03063         }
03064     }
03065     MEMFREE(charray);
03066     free_mbuf(temp);
03067     free_mbuf(buf);
03068     raw_notify(executor, "-- End of list of Channels --");
03069 }
03070 
03071 // Returns a player's comtitle for a named channel.
03072 //
03073 FUNCTION(fun_comtitle)
03074 {
03075     UNUSED_PARAMETER(caller);
03076     UNUSED_PARAMETER(enactor);
03077     UNUSED_PARAMETER(nfargs);
03078     UNUSED_PARAMETER(cargs);
03079     UNUSED_PARAMETER(ncargs);
03080 
03081     if (!mudconf.have_comsys)
03082     {
03083         safe_str("#-1 COMSYS DISABLED", buff, bufc);
03084         return;
03085     }
03086 
03087     dbref victim = lookup_player(executor, fargs[0], true);
03088     if (!Good_obj(victim))
03089     {
03090         init_match(executor, fargs[0], TYPE_THING);
03091         match_everything(0);
03092         victim = match_result();
03093         if (!Good_obj(victim))
03094         {
03095             safe_str("#-1 OBJECT DOES NOT EXIST", buff, bufc);
03096             return;
03097         }
03098     }
03099 
03100     struct channel *chn = select_channel(fargs[1]);
03101     if (!chn)
03102     {
03103         safe_str("#-1 CHANNEL DOES NOT EXIST", buff, bufc);
03104         return;
03105     }
03106 
03107     comsys_t *c = get_comsys(executor);
03108     struct comuser *user;
03109 
03110     int i;
03111     bool onchannel = false;
03112     if (Wizard(executor))
03113     {
03114         onchannel = true;
03115     }
03116     else
03117     {
03118         for (i = 0; i < c->numchannels; i++)
03119         {
03120             user = select_user(chn, executor);
03121             if (user)
03122             {
03123                 onchannel = true;
03124                 break;
03125             }
03126         }
03127     }
03128 
03129     if (!onchannel)
03130     {
03131         safe_noperm(buff, bufc);
03132         return;
03133     }
03134 
03135     for (i = 0; i < c->numchannels; i++)
03136     {
03137         user = select_user(chn, victim);
03138         if (user)
03139         {
03140           // Do we want this function to evaluate the comtitle or not?
03141 #if 0
03142           char *nComTitle = GetComtitle(user);
03143           safe_str(nComTitle, buff, bufc);
03144           FreeComtitle(nComTitle);
03145           return;
03146 #else
03147           safe_str(user->title, buff, bufc);
03148           return;
03149 #endif
03150         }
03151     }
03152     safe_str("#-1 OBJECT NOT ON THAT CHANNEL", buff, bufc);
03153 }
03154 
03155 // Returns a player's comsys alias for a named channel.
03156 //
03157 FUNCTION(fun_comalias)
03158 {
03159     UNUSED_PARAMETER(caller);
03160     UNUSED_PARAMETER(enactor);
03161     UNUSED_PARAMETER(nfargs);
03162     UNUSED_PARAMETER(cargs);
03163     UNUSED_PARAMETER(ncargs);
03164 
03165     if (!mudconf.have_comsys)
03166     {
03167         safe_str("#-1 COMSYS DISABLED", buff, bufc);
03168         return;
03169     }
03170 
03171     dbref victim = lookup_player(executor, fargs[0], true);
03172     if (!Good_obj(victim))
03173     {
03174         init_match(executor, fargs[0], TYPE_THING);
03175         match_everything(0);
03176         victim = match_result();
03177         if (!Good_obj(victim))
03178         {
03179             safe_str("#-1 OBJECT DOES NOT EXIST", buff, bufc);
03180             return;
03181         }
03182     }
03183 
03184     struct channel *chn = select_channel(fargs[1]);
03185     if (!chn)
03186     {
03187         safe_str("#-1 CHANNEL DOES NOT EXIST", buff, bufc);
03188         return;
03189     }
03190 
03191     // Wizards can get the comalias for anyone. Players and objects can check
03192     // for themselves. Objects that Inherit can check for their owners.
03193     //
03194     if (  !Wizard(executor)
03195        && executor != victim
03196        && (  Owner(executor) != victim
03197           || !Inherits(executor)))
03198     {
03199         safe_noperm(buff, bufc);
03200         return;
03201     }
03202 
03203     comsys_t *cc = get_comsys(victim);
03204     for (int i = 0; i < cc->numchannels; i++)
03205     {
03206         if (!strcmp(fargs[1], cc->channels[i]))
03207         {
03208             safe_str(cc->alias + i * ALIAS_SIZE, buff, bufc);
03209             return;
03210         }
03211     }
03212     safe_str("#-1 OBJECT NOT ON THAT CHANNEL", buff, bufc);
03213 }
03214 
03215 // Returns a list of channels.
03216 //
03217 FUNCTION(fun_channels)
03218 {
03219     UNUSED_PARAMETER(caller);
03220     UNUSED_PARAMETER(enactor);
03221     UNUSED_PARAMETER(cargs);
03222     UNUSED_PARAMETER(ncargs);
03223 
03224     if (!mudconf.have_comsys)
03225     {
03226         safe_str("#-1 COMSYS DISABLED", buff, bufc);
03227         return;
03228     }
03229 
03230     dbref who = NOTHING;
03231     if (nfargs >= 1)
03232     {
03233         who = lookup_player(executor, fargs[0], true);
03234         if (  who == NOTHING
03235            && mux_stricmp(fargs[0], "all") != 0)
03236         {
03237             safe_str("#-1 PLAYER NOT FOUND", buff, bufc);
03238             return;
03239         }
03240     }
03241 
03242     ITL itl;
03243     ItemToList_Init(&itl, buff, bufc);
03244     struct channel *chn;
03245     for (chn = (struct channel *)hash_firstentry(&mudstate.channel_htab);
03246          chn;
03247          chn = (struct channel *)hash_nextentry(&mudstate.channel_htab))
03248     {
03249         if (  (  Comm_All(executor)
03250               || (chn->type & CHANNEL_PUBLIC)
03251               || Controls(executor, chn->charge_who))
03252            && (  who == NOTHING
03253               || Controls(who, chn->charge_who))
03254            && !ItemToList_AddString(&itl, chn->name))
03255         {
03256             break;
03257         }
03258     }
03259 }

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