tinymux/mux/include/comsys.h
Stephen Dennis 8808b4c375 feat(#2136): flip fargs to const UTF8 * const — and convert every site the compiler surfaced
The flip: FUNCTION/XFUNCTION/FUN::fun/delim_check and the module
interfaces take `const UTF8 * const fargs[]`.  Double-const is
load-bearing: C++ qualification conversion needs const at both pointer
levels, so builder-side `UTF8 *[]` arrays convert implicitly — the
evaluator, the JIT marshaller, and every owner site need zero casts,
and slot reassignment inside bodies becomes a compile error for free.

The conversions: the flip landed first so the compiler enumerated every
violation; this commit is that inventory worked to zero — ~250 sites
across funceval, funceval2, functions, funmath, help, mail, session,
powers, levels, predicates, conf, walkdb, stringutil, timeutil/
date_scan (regenerated, one-line diff), exp3, and mux_main, each
classified per docs/campaign-2136-const-fargs.md's four recipes.

New idioms (functions.h): trim_space_sep_n() — non-destructive trim for
(pointer, length) consumers, so trim-then-scan sites need no copy at
all; FargVec — the argv counterpart of FargCopy for CS_ARGV handlers.
countwords() and DecodeListOfIntegers() rewritten non-destructive.

The flip deleted more than it added: #2157's fun_munge list1 copy, the
engine_com help-topic copy, fun_index's in-place NUL write, and five
const_casts (process_sex x4, sha1_helper).  const_cast budget: zero
added.

Trap recorded in the brief: an old-signature definition doesn't fail
the build — it becomes a C++ overload, and the new-signature symbol
stays undefined until dlopen(RTLD_NOW).  delim_check, the conn_bridge
bridges, the dbt_spike stub, and exp3::Call were all silently shadowed;
muxscript was the only host that noticed, because netmux's own net.cpp
resolved the flat-namespace lookup.  After any signature flip, grep the
old spelling.

Verified: make test EXPECT_CONFIG="jit=yes" (35 passed / 0 failed) and
make test-scenario, including the new tests/scenario/sidefx_fargs.py
that live-probes the class-3 wrappers smoke never touches (pemit/
trigger/link/tel/wipe/destroy).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 14:34:23 -06:00

262 lines
8.5 KiB
C++

/*! \file comsys.h
* \brief Channel Communication System.
*
*/
#ifndef COMSYS_H
#define COMSYS_H
#include <map>
#include <string>
#include <vector>
#ifndef NOTHING
#define NOTHING (-1)
#endif
//! \def MAX_USERS_PER_CHANNEL
// Maximum Users Per Channel
#define MAX_USERS_PER_CHANNEL 1000000
//! \def MAX_CHANNEL_LEN
// Maximum length for channel names
#define MAX_CHANNEL_LEN 50
//! \def MAX_HEADER_LEN
// Maximum length for channel headers (display names)
#define MAX_HEADER_LEN 100
//! \def MAX_TITLE_LEN
// Maximum length for Player titles for channels
#define MAX_TITLE_LEN 200
//! \def MAX_ALIAS_LEN
// Maximum length for an alias to a channel
#define MAX_ALIAS_LEN 15
//! \def MAX_COST
// Maximum cost to use for a channel
#define MAX_COST 32767
//! \struct com_alias
// Per-player alias entry — pairs an alias string with its channel name.
struct com_alias
{
std::string alias;
std::string channel;
};
//! \struct comuser
// Comsys user data
struct comuser
{
//! dbref of the user
dbref who;
//! Is the user on the channel
bool bUserIsOn;
//! Per channel display name
std::string title;
//! Status of the title
bool ComTitleStatus;
//! Whether join/leave messages are suppressed for this user
bool bGagJoinLeave;
//! Whether the player is currently connected to the MUD
bool bConnected;
comuser() : who(NOTHING), bUserIsOn(false),
ComTitleStatus(true), bGagJoinLeave(false), bConnected(false) {}
};
//! \struct channel
// Channel data for Comsys
struct channel
{
//! Name of the Channel
UTF8 name[MAX_CHANNEL_LEN+1];
//! Header / Display Name of the channel
UTF8 header[MAX_HEADER_LEN+1];
//! Flag data for channel
int type;
int temp1;
int temp2;
//! Cost for channel usage
int charge;
//! Person to charge for usage
dbref charge_who;
int amount_col;
//! Channel object if set
dbref chan_obj;
//! Users on the channel, keyed by dbref
std::map<dbref, comuser> users;
//! Number of messages sent on the channel
int num_messages;
channel() : type(0), temp1(0), temp2(0), charge(0),
charge_who(NOTHING), amount_col(0), chan_obj(NOTHING),
num_messages(0)
{
memset(name, 0, sizeof(name));
memset(header, 0, sizeof(header));
}
};
//! \struct comsys_t
// Data for storing user information for players on channels
struct comsys_t
{
//! DBREF of the user
dbref who;
//! Alias/channel pairs for this player
std::vector<com_alias> aliases;
comsys_t() : who(NOTHING) {}
};
//! \brief Save communication system data to disk
//! \param filename - file to use for for writing data
void save_comsys(UTF8 *filename);
//! \brief Save user aliases on a per-channel basis
//! \param fp - FILE pointer used for writing data
void save_channels(FILE *fp);
//! \brief Save channel data and some user state for each user on the channel
void save_comsystem(FILE *fp);
//! \brief Open file and load comsystem data from disk
//! \param filename - filename to open for reading
void load_comsys(UTF8 *filename);
//! \brief Delete comsystem information for the given dbref
void del_comsys(dbref who);
//! \brief Add player as an active member of the given channel
//! \param player - dbref of player to add
//! \param ch - comsys channel pointer to add to
void do_joinchannel(dbref player, struct channel *ch);
//! \brief Remove disconnecting player from the active user list for all channels
//! \param player - dbref to remove
void do_comdisconnect(dbref player);
//! \brief Remove player from the active user list of channel
//! \param player - dbref of the player to remove
//! \param channel - name of the channel
void do_comdisconnectchannel(dbref player, UTF8 *channel);
//! \brief Handle connecting player channel activations
//! \param player - dbref of the connecting player to process
void do_comconnect(dbref player);
//! \brief Remove objects with no channels or objects that are destroyed
void purge_comsystem(void);
//! Sort aliases for the given comsys_t data
void sort_com_aliases(comsys_t &c);
//! \brief Xmit messages to the listening objects on channel & log data
//! \param player - dbref of executor
//! \param ch - channel data to transmit the message on
//! \param msgNormal - message to send with comtitle
//! \param msgNoComtitle - message to send w/o comtitle
void SendChannelMessage(dbref player, struct channel *ch, UTF8 *msgNormal,
UTF8 *msgNoComtitle, bool bJoinLeaveMsg = false);
//! \brief Process '<alias> who' command to show online channel users
//! \brief player - enacting player
//! \brief ch - channel to display
void do_comwho(dbref player, struct channel *ch);
//! \brief Display message history for a particular channel
//! \param player - requesting player
//! \param ch - channel to determine history for
//! \param arg - number of historical messages to display
void do_comlast(dbref player, struct channel *ch, int arg);
//! \brief Process a player request to temporary leave a channel
//! \param player - player to remove
//! \param ch - channel to remove the player from
void do_leavechannel(dbref player, struct channel *ch);
//! \brief Process a channel removal for player ("delcom")
//! \param player - player to remove
//! \param channel - channel name to remove
//! \param quiet - show messages or not
void do_delcomchannel(dbref player, UTF8 *channel, bool bQuiet);
//! \brief Clear all channel subscriptions for the enactor ("clearcom")
void do_clearcom(dbref executor, dbref caller, dbref enactor, int eval, int key);
//! \brief Add a new channel subscription/alias for the enactor
void do_addcom(dbref executor, dbref caller, dbref enactor, int eval, int key, int nargs,
UTF8 *arg1, UTF8 *arg2, const UTF8 *cargs[], int ncargs);
//! \brief Process a request to set a channel header
//! \param player - player requesting the change
//! \param channel - channel name to change
//! \param header - new header to use
void do_cheader(dbref player, UTF8 *channel, const UTF8 *header);
//! \brief Locate a channel structure by channel name
//! \param channel_name - name of channel to locate
//! @return struct channel pointer or nullptr if not found
struct channel *select_channel(const UTF8 *channel_name);
//! \brief Locate player in the user list for the given channel
//! \param ch - channel data to search
//! \param player - dbref of the player to locate
//! @return nullptr if not found, or struct comuser pointer
struct comuser *select_user(struct channel *ch, dbref player);
//! \brief Validate alias limits of 1-5 characters, no spaces, no ANSI
//! \param pAlias - incoming alias
//! \param nValidAlias - return size of the valid alias
//! \param bValidAlias - is alias valid or not
//! \return new alias data or nullptr on failure
UTF8 *MakeCanonicalComAlias(const UTF8 *pAlias, size_t *nValidAlias,
bool *bValidAlias);
//! \brief Purge channels owned by player. Internal cleanup called from db.c
//! \param player - dbref of cleanup target
void do_channelnuke(dbref player);
//! \brief Process comsys related commands 'alias <cmd>' (from command.cpp)
//! \param who - enactor
//! \param cmd - command to process
//! \return true to continue searching command matches, false to stop
bool do_comsystem(dbref who, UTF8 *cmd);
//! \brief Check if player can join a channel
//! \param player - player to check for join access
//! \param chan - channel to check
//! \return true if allowed, false if denied
bool test_join_access(dbref player, struct channel *chan);
//! \brief Check if player can transmit on a channel
//! \param player - player to check for join access
//! \param chan - channel to check
//! \return true if allowed, false if denied
bool test_transmit_access(dbref player, struct channel *chan);
//! \brief Check if player can receive channel transmission
//! \param player - player to check for join access
//! \param chan - channel to check
//! \return true if allowed, false if denied
bool test_receive_access(dbref player, struct channel *chan);
#define CHANNEL_PLAYER_JOIN (0x00000001UL)
#define CHANNEL_PLAYER_TRANSMIT (0x00000002UL)
#define CHANNEL_PLAYER_RECEIVE (0x00000004UL)
#define CHANNEL_OBJECT_JOIN (0x00000010UL)
#define CHANNEL_OBJECT_TRANSMIT (0x00000020UL)
#define CHANNEL_OBJECT_RECEIVE (0x00000040UL)
#define CHANNEL_LOUD (0x00000100UL)
#define CHANNEL_PUBLIC (0x00000200UL)
#define CHANNEL_SPOOF (0x00000400UL)
// Connected players and non-garbage objects are ok.
//
#define UNDEAD(x) (Good_obj(x) && ((Typeof(x) != TYPE_PLAYER) || Connected(x)))
#endif // !COMSYS_H