static void free_channel(CHAN *c);
static void free_chanlist(CHANLIST *cl);
static void free_user(CHANUSER *u);
-static int load_chatdb_oldstyle(FILE * fp);
-static int load_channel(FILE * fp, CHAN *ch);
-static int load_chanusers(FILE * fp, CHAN *ch);
-static int load_labeled_channel(FILE * fp, CHAN *ch);
-static int load_labeled_chanusers(FILE * fp, CHAN *ch);
+static int load_chatdb_oldstyle(PENNFILE *fp);
+static int load_channel(PENNFILE *fp, CHAN *ch);
+static int load_chanusers(PENNFILE *fp, CHAN *ch);
+static int load_labeled_channel(PENNFILE *fp, CHAN *ch, int dbflags);
+static int load_labeled_chanusers(PENNFILE *fp, CHAN *ch);
static void insert_channel(CHAN **ch);
static void remove_channel(CHAN *ch);
static void insert_obj_chan(dbref who, CHAN **ch);
void chan_chownall(dbref old, dbref new);
static int insert_user(CHANUSER *user, CHAN *ch);
static int remove_user(CHANUSER *u, CHAN *ch);
-static int save_channel(FILE * fp, CHAN *ch);
-static int save_chanuser(FILE * fp, CHANUSER *user);
+static int save_channel(PENNFILE *fp, CHAN *ch);
+static int save_chanuser(PENNFILE *fp, CHANUSER *user);
static void channel_wipe(dbref player, CHAN *chan);
static int yesno(const char *str);
static int canstilladd(dbref player);
static void do_channel_who(dbref player, CHAN *chan);
void chat_player_announce(dbref player, char *msg, int ungag);
static int ok_channel_name(const char *n);
+/*
static void format_channel_chat(CHAN *chan, CHANUSER *u, dbref victim,
int flags, const char *msg, const char *extra);
+ */
+static void channel_send(CHAN *channel, dbref player, int flags,
+ const char *origmessage);
static void list_partial_matches(dbref player, const char *name,
enum chan_match_type type);
slab *chanlist_slab; /**< slab for 'struct chanlist' allocations */
slab *chanuser_slab; /**< slab for 'struct chanuser' allocations */
-#define YES 1 /**< An affirmative. */
-#define NO 0 /**< A negative. */
-#define ERR -1 /**< An error. Clever, eh? */
+#define CHAN_YES 1 /**< An affirmative. */
+#define CHAN_NO 0 /**< A negative. */
+#define CHAN_ERR -1 /**< An error. Clever, eh? */
/** Wrapper for insert_user() that generates a new CHANUSER and inserts it */
#define insert_user_by_dbref(who,chan) \
{"Admin", 'A', CHANNEL_ADMIN | CHANNEL_PLAYER, CHANNEL_ADMIN},
{"Director", 'W', CHANNEL_DIRECTOR | CHANNEL_PLAYER, CHANNEL_DIRECTOR},
{"Player", 'P', CHANNEL_PLAYER, CHANNEL_PLAYER},
+ {"Thing", 'T', CHANNEL_OBJECT, CHANNEL_OBJECT},
{"Object", 'O', CHANNEL_OBJECT, CHANNEL_OBJECT},
{"Quiet", 'Q', CHANNEL_QUIET, CHANNEL_QUIET},
{"Open", 'o', CHANNEL_OPEN, CHANNEL_OPEN},
* \retval 0 failure
*/
static int
-load_chatdb_oldstyle(FILE * fp)
+load_chatdb_oldstyle(PENNFILE *fp)
{
int i;
CHAN *ch;
/* Load all channels */
for (i = 0; i < num_channels; i++) {
- if (feof(fp))
+ if (penn_feof(fp))
break;
ch = new_channel();
if (!ch)
num_channels = i;
/* Check for **END OF DUMP*** */
- if (!fgets(buff, sizeof buff, fp))
+ if (!penn_fgets(buff, sizeof buff, fp))
do_rawlog(LT_ERR, T("CHAT: No end-of-dump marker in the chat database."));
else if (strcmp(buff, EOD) != 0)
do_rawlog(LT_ERR, T("CHAT: Trailing garbage in the chat database."));
* \retval 0 failure
*/
int
-load_chatdb(FILE * fp)
+load_chatdb(PENNFILE *fp)
{
int i, flags;
CHAN *ch;
char buff[20];
char *chat_timestamp;
- i = fgetc(fp);
+ i = penn_fgetc(fp);
if (i == EOF) {
do_rawlog(LT_ERR, T("CHAT: Invalid database format!"));
longjmp(db_err, 1);
} else if (i != '+') {
- ungetc(i, fp);
+ penn_ungetc(i, fp);
return load_chatdb_oldstyle(fp);
}
- i = fgetc(fp);
+ i = penn_fgetc(fp);
if (i != 'V') {
do_rawlog(LT_ERR, T("CHAT: Invalid database format!"));
ch = new_channel();
if (!ch)
return 0;
- if (!load_labeled_channel(fp, ch)) {
+ if (!load_labeled_channel(fp, ch, flags)) {
do_rawlog(LT_ERR, T("Unable to load channel %d."), i);
free_channel(ch);
return 0;
num_channels = i;
/* Check for **END OF DUMP*** */
- if (!fgets(buff, sizeof buff, fp))
+ if (!penn_fgets(buff, sizeof buff, fp))
do_rawlog(LT_ERR, T("CHAT: No end-of-dump marker in the chat database."));
else if (strcmp(buff, EOD) != 0)
do_rawlog(LT_ERR, T("CHAT: Trailing garbage in the chat database."));
ch->title[0] = '\0';
ChanType(ch) = CHANNEL_DEFAULT_FLAGS;
ChanCreator(ch) = NOTHING;
+ ChanMogrifier(ch) = NOTHING;
ChanCost(ch) = CHANNEL_COST;
ChanNext(ch) = NULL;
ChanNumMsgs(ch) = 0;
* successful, 0 otherwise.
*/
static int
-load_channel(FILE * fp, CHAN *ch)
+load_channel(PENNFILE *fp, CHAN *ch)
{
mush_strncpy(ChanName(ch), getstring_noalloc(fp), CHAN_NAME_LEN);
- if (feof(fp))
+ if (penn_feof(fp))
return 0;
mush_strncpy(ChanTitle(ch), getstring_noalloc(fp), CHAN_TITLE_LEN);
ChanType(ch) = (privbits) getref(fp);
ChanCreator(ch) = getref(fp);
+ ChanMogrifier(ch) = NOTHING;
ChanCost(ch) = getref(fp);
ChanNumMsgs(ch) = 0;
ChanJoinLock(ch) = getboolexp(fp, chan_join_lock);
* successful, 0 otherwise.
*/
static int
-load_labeled_channel(FILE * fp, CHAN *ch)
+load_labeled_channel(PENNFILE *fp, CHAN *ch, int dbflags)
{
char *tmp;
int i;
ChanCreator(ch) = d;
db_read_this_labeled_int(fp, "cost", &i);
ChanCost(ch) = i;
+ if (dbflags & CDB_SPIFFY) {
+ db_read_this_labeled_int(fp, "buffer", &i);
+ if (i)
+ ChanBufferQ(ch) = allocate_bufferq(i);
+ db_read_this_labeled_dbref(fp, "mogrifier", &d);
+ ChanMogrifier(ch) = d;
+ }
ChanNumMsgs(ch) = 0;
while (1) {
db_read_labeled_string(fp, &label, &value);
/* Load the *channel's user list. Return number of users on success, or 0 */
static int
-load_chanusers(FILE * fp, CHAN *ch)
+load_chanusers(PENNFILE *fp, CHAN *ch)
{
int i, num = 0;
CHANUSER *user;
/* Load the *channel's user list. Return number of users on success, or 0 */
static int
-load_labeled_chanusers(FILE * fp, CHAN *ch)
+load_labeled_chanusers(PENNFILE *fp, CHAN *ch)
{
int i, num = 0, n;
char *tmp;
CHANLIST *p, *nextp;
for (p = Chanlist(thing); p; p = nextp) {
nextp = p->next;
+ if (ChanMogrifier(p->chan) == thing) {
+ ChanMogrifier(p->chan) = NOTHING;
+ }
remove_user_by_dbref(thing, p->chan);
}
return;
* \retval 0 failure
*/
int
-save_chatdb(FILE * fp)
+save_chatdb(PENNFILE *fp)
{
CHAN *ch;
int default_flags = 0;
/* How many channels? */
- OUTPUT(fprintf(fp, "+V%d\n", default_flags));
+ penn_fprintf(fp, "+V%d\n", default_flags);
db_write_labeled_string(fp, "savedtime", show_time(mudtime, 1));
db_write_labeled_int(fp, "channels", num_channels);
for (ch = channels; ch; ch = ch->next) {
save_channel(fp, ch);
}
- OUTPUT(fputs(EOD, fp));
+ penn_fputs(EOD, fp);
return 1;
}
/* Save a single channel. Return 1 if successful, 0 otherwise.
*/
static int
-save_channel(FILE * fp, CHAN *ch)
+save_channel(PENNFILE *fp, CHAN *ch)
{
CHANUSER *cu;
db_write_labeled_int(fp, " flags", ChanType(ch));
db_write_labeled_dbref(fp, " creator", ChanCreator(ch));
db_write_labeled_int(fp, " cost", ChanCost(ch));
+ db_write_labeled_int(fp, " buffer", bufferq_blocks(ChanBufferQ(ch)));
+ db_write_labeled_dbref(fp, " mogrifier", ChanMogrifier(ch));
db_write_labeled_string(fp, " lock", "join");
putboolexp(fp, ChanJoinLock(ch));
db_write_labeled_string(fp, " lock", "speak");
/* Save the channel's user list. Return 1 on success, 0 on failure */
static int
-save_chanuser(FILE * fp, CHANUSER *user)
+save_chanuser(PENNFILE *fp, CHANUSER *user)
{
db_write_labeled_dbref(fp, " dbref", CUdbref(user));
db_write_labeled_int(fp, " flags", CUtype(user));
T("CHAT: You join %s to channel <%s>."), Name(victim),
ChanName(chan));
u = onchannel(victim, chan);
+ ChanNumUsers(chan)++;
if (!Channel_Quiet(chan) && !DarkLegal(victim)) {
- format_channel_chat(chan, u, victim, CB_CHECKQUIET | CB_PRESENCE,
- T("%s has joined this channel."), NULL);
+ channel_send(chan, victim, CB_CHECKQUIET | CB_PRESENCE | CB_POSE,
+ T("%s has joined this channel."));
}
- ChanNumUsers(chan)++;
} else {
notify_format(player,
T("%s is already on channel <%s>."), Name(victim),
strcpy(title, (u && CUtitle(u)) ? CUtitle(u) : "");
if (remove_user(u, chan)) {
if (!Channel_Quiet(chan) && !DarkLegal(victim)) {
- format_channel_chat(chan, NULL, victim,
- CB_CHECKQUIET | CB_PRESENCE,
- T("%s has left this channel."), title);
+ channel_send(chan, victim,
+ CB_CHECKQUIET | CB_PRESENCE | CB_POSE,
+ T("has left this channel."));
}
notify_format(victim,
T("CHAT: %s removes you from channel <%s>."),
/* Does victim pass the joinlock? */
if (!Chan_Can_Join(chan, player)) {
if (Director(player)) {
- /* Directors can override join locks */
+ /* Wizards can override join locks */
notify(player,
T
- ("CHAT: Warning: You don't meet channel join permissions (joining anyway)"));
+ ("CHAT: Warning: You don't meet channel join permissions! (joining anyway)"));
} else {
notify(player, T("Permission to join denied."));
return;
if (insert_user_by_dbref(player, chan)) {
notify_format(player, T("CHAT: You join channel <%s>."), ChanName(chan));
u = onchannel(player, chan);
- if (!Channel_Quiet(chan) && !DarkLegal(player))
- format_channel_chat(chan, u, player, CB_CHECKQUIET | CB_PRESENCE,
- T("%s has joined this channel."), NULL);
ChanNumUsers(chan)++;
+ if (!Channel_Quiet(chan) && !DarkLegal(player))
+ channel_send(chan, player,
+ CB_CHECKQUIET | CB_PRESENCE | CB_POSE,
+ T("has joined this channel."));
} else {
/* Should never happen */
notify_format(player,
strcpy(title, (u && CUtitle(u)) ? CUtitle(u) : "");
if (remove_user(u, chan)) {
if (!Channel_Quiet(chan) && !DarkLegal(player))
- format_channel_chat(chan, NULL, player, CB_CHECKQUIET | CB_PRESENCE,
- T("%s has left this channel."), title);
+ channel_send(chan, player,
+ CB_CHECKQUIET | CB_PRESENCE | CB_POSE,
+ T("has left this channel."));
notify_format(player, T("CHAT: You leave channel <%s>."), ChanName(chan));
} else {
/* Should never happen */
CHANUSER *u;
const char *gap;
char type;
- const char *someone = "Someone";
- char *title;
- const char *name;
bool canhear;
if (!Chan_Ok_Type(chan, player)) {
return;
}
- if (!Channel_NoTitles(chan) && u && CUtitle(u) && *CUtitle(u))
- title = CUtitle(u);
- else
- title = NULL;
- if (Channel_NoNames(chan))
- name = NULL;
- else
- name = accented_name(player);
- if (!title && !name)
- name = someone;
-
/* figure out what kind of message we have */
gap = " ";
type = ':';
/* FALLTHRU */
case POSE_TOKEN:
arg1 = arg1 + 1;
- channel_chat(chan, player, 0, arg1, type, "<%s> %s%s%s%s%s%s",
- ChanName(chan), title ? title : "", title ? ANSI_ENDALL : "",
- (title && name) ? " " : "", name ? name : "", gap, arg1);
- if (!canhear)
- notify_format(player, T("To channel %s: %s%s%s%s%s%s"), ChanName(chan),
- title ? title : "", title ? ANSI_ENDALL : "",
- (title && name) ? " " : "", name ? name : "", gap, arg1);
+ channel_send(chan, player, type == ';' ? CB_SEMIPOSE : CB_POSE, arg1);
break;
default:
if (CHAT_STRIP_QUOTE && (*arg1 == SAY_TOKEN))
arg1 = arg1 + 1;
- channel_chat(chan, player, 0, arg1, '"', T("<%s> %s%s%s%s says, \"%s\""),
- ChanName(chan), title ? title : "",
- title ? ANSI_ENDALL : "", (title && name) ? " " : "",
- name ? name : "", arg1);
- if (!canhear)
- notify_format(player,
- T("To channel %s: %s%s%s%s says, \"%s\""),
- ChanName(chan), title ? title : "",
- title ? ANSI_ENDALL : "", (title && name) ? " " : "",
- name ? name : "", arg1);
+ channel_send(chan, player, CB_SPEECH, arg1);
break;
}
CHAN *chan = NULL;
CHANUSER *u;
int canhear;
- int override_checks = 0;
if (!name || !*name) {
notify(player, T("That is not a valid channel."));
notify(player, T("CHAT: I don't recognize that channel."));
return;
}
- /* If the cemitter is both See_All and Pemit_All, always allow them
- * to @cemit, as they could iterate over connected players, examine
- * their channels, and pemit to them anyway.
- */
- if (!override_checks && !Chan_Ok_Type(chan, player)) {
+
+ if (!Chan_Ok_Type(chan, player)) {
notify_format(player,
T
("Sorry, you're not the right type to be on channel <%s>."),
ChanName(chan));
return;
}
- if (!override_checks && !Chan_Can_Cemit(chan, player)) {
+ if (!Chan_Can_Cemit(chan, player)) {
notify_format(player,
T("Sorry, you're not allowed to @cemit on channel <%s>."),
ChanName(chan));
u = onchannel(player, chan);
canhear = u ? !Chanuser_Gag(u) : 0;
/* If the channel isn't open, you must hear it in order to speak */
- if (!override_checks && !Channel_Open(chan)) {
+ if (!Channel_Open(chan)) {
if (!u) {
notify(player, T("You must be on that channel to speak on it."));
return;
return;
}
if (!(flags & PEMIT_SILENT))
- channel_chat(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF,
- msg, '|', "<%s> %s", ChanName(chan), msg);
+ channel_send(chan, player, CB_EMIT, msg);
else
- channel_chat(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF,
- msg, '|', "%s", msg);
+ channel_send(chan, player, CB_EMIT | CB_QUIET, msg);
if (!canhear)
notify_format(player, T("Cemit to channel %s: %s"), ChanName(chan), msg);
ChanNumMsgs(chan)++;
if (type)
ChanType(chan) = type;
ChanCreator(chan) = Owner(player);
+ ChanMogrifier(chan) = NOTHING;
mush_strncpy(ChanName(chan), name, CHAN_NAME_LEN);
insert_channel(&chan);
notify_format(player, T("CHAT: Channel <%s> created."), ChanName(chan));
insert_channel(&chan);
snprintf(announcebuff, BUFFER_LEN, "has renamed %s to %s",
old, ChanName(chan));
- channel_chat(chan, player, 0, announcebuff, '@',
- "<%s> %s has renamed channel %s to %s.",
- ChanName(chan), Name(player), old, ChanName(chan));
+ channel_send(chan, player,
+ CB_CHECKQUIET | CB_PRESENCE | CB_POSE, announcebuff);
notify(player, T("Channel renamed."));
break;
case 3:
return;
}
+/** Change the mogrifier of a channel.
+ * \verbatim
+ * This is the top-level function for @channel/mogrifier
+ * \endverbatim
+ * \param player the enactor.
+ * \param name name of the channel.
+ * \param newobj name of the new mogrifier object.
+ */
+void
+do_chan_set_mogrifier(dbref player, const char *name, const char *newobj)
+{
+ CHAN *c;
+ dbref it = NOTHING;
+ /* Find the channel */
+ test_channel(player, name, c);
+
+ /* Only a channel modifier can do this. */
+ if (!Chan_Can_Modify(c, player)) {
+ notify(player, T("CHAT: Only a channel modifier can do that."));
+ return;
+ }
+
+ /* Find the mogrifying object */
+ if (newobj && *newobj) {
+ if ((it = match_result(player, newobj, NOTYPE, MAT_EVERYTHING)) < 0) {
+ if (it == NOTHING)
+ notify(player, T("I can't see that here."));
+ else if (it == AMBIGUOUS)
+ notify(player, T("I don't know which thing you mean."));
+ return;
+ }
+ } else if (ChanMogrifier(c) != NOTHING) {
+ notify_format(player,
+ T("CHAT: Channel <%s> no longer mogrified by %s."),
+ ChanName(c), Name(ChanMogrifier(c)));
+ ChanMogrifier(c) = NOTHING;
+ return;
+ } else {
+ notify_format(player,
+ T("CHAT: Channel <%s> isn't being mogrified."), ChanName(c));
+ return;
+ }
+
+ /* The player must be able to *control* the mogrifier. */
+ if (!controls(player, it)) {
+ notify(player, T("CHAT: You must control the mogrifier."));
+ return;
+ }
+ ChanMogrifier(c) = it;
+ notify_format(player,
+ T("CHAT: Channel <%s> now mogrified by %s."), ChanName(c),
+ Name(it));
+ return;
+}
+
/** Change the owner of a channel.
* \verbatim
* This is the top-level function for @channel/chown, which changes
notify(player, ChanName(c));
notify_format(player, T("Description: %s"), ChanTitle(c));
notify_format(player, T("Owner: %s"), Name(ChanCreator(c)));
+ if (ChanMogrifier(c) != NOTHING) {
+ notify_format(player, T("Mogrifier: %s (#%d)"),
+ Name(ChanMogrifier(c)), ChanMogrifier(c));
+ }
notify_format(player, T("Flags: %s"),
privs_to_string(priv_table, ChanType(c)));
if (ChanBufferQ(c))
strcpy(cleanp, remove_markup(ChanName(c), NULL));
if (string_prefix(cleanp, cleanname)) {
found++;
- if (!(See_All(player) || Chan_Can_Modify(c, player)
+ if (!(CanSee(player, ChanCreator(c)) || Chan_Can_Modify(c, player)
|| (ChanCreator(c) == player))) {
if (Chan_Can_See(c, player))
notify_format(player, T("CHAT: No permission to decompile <%s>"),
privs_to_string(priv_table, ChanType(c)));
notify_format(player, "@channel/chown %s = %s", ChanName(c),
Name(ChanCreator(c)));
+ if (ChanMogrifier(c) != NOTHING) {
+ notify_format(player, "@channel/mogrifier %s = #%d", ChanName(c),
+ ChanMogrifier(c));
+ }
if (ChanModLock(c) != TRUE_BOOLEXP)
notify_format(player, "@clock/mod %s = %s", ChanName(c),
unparse_boolexp(player, ChanModLock(c), UB_MEREF));
FUNCTION(fun_cwho)
{
int first = 1;
+ int matchcond = 0;
+ int priv = 0;
+ int show;
CHAN *chan = NULL;
CHANUSER *u;
dbref who;
break;
}
+ if (nargs == 2) {
+ if (!strcasecmp(args[1], "on"))
+ matchcond = 0;
+ else if (!strcasecmp(args[1], "off"))
+ matchcond = 1;
+ else if (!strcasecmp(args[1], "all"))
+ matchcond = 2;
+ else {
+ safe_str(T("#-1 INVALID ARGUMENT"), buff, bp);
+ return;
+ }
+ }
+
/* Feh. We need to do some sort of privilege checking, so that
* if mortals can't do '@channel/who wizard', they can't do
* 'think cwho(wizard)' either. The first approach that comes to
safe_str(T("#-1 NO PERMISSIONS FOR CHANNEL"), buff, bp);
return;
}
+
+ priv = Priv_Who(executor);
+
for (u = ChanUsers(chan); u; u = u->next) {
who = CUdbref(u);
- if ((IsThing(who) || Connected(who)) &&
- (!Chanuser_Hide(u) || Priv_Who(executor))) {
- if (first)
- first = 0;
+ show = 1;
+ if (!IsThing(who) && matchcond != 2) {
+ if (matchcond)
+ show = !Connected(who) || (Chanuser_Hide(u) && !priv);
else
- safe_chr(' ', buff, bp);
- safe_dbref(who, buff, bp);
+ show = Connected(who) && (!Chanuser_Hide(u) || priv);
}
+ if (!show)
+ continue;
+ if (first)
+ first = 0;
+ else
+ safe_chr(' ', buff, bp);
+ safe_dbref(who, buff, bp);
}
}
yesno(const char *str)
{
if (!str || !*str)
- return ERR;
+ return CHAN_ERR;
switch (str[0]) {
case 'y':
case 'Y':
- return YES;
+ return CHAN_YES;
case 'n':
case 'N':
- return NO;
+ return CHAN_NO;
case 'o':
case 'O':
switch (str[1]) {
case 'n':
case 'N':
- return YES;
+ return CHAN_YES;
case 'f':
case 'F':
- return NO;
+ return CHAN_NO;
default:
- return ERR;
+ return CHAN_ERR;
}
default:
- return ERR;
+ return CHAN_ERR;
}
}
if (u) {
if (!Channel_Quiet(c) && (Channel_Admin(c) || Channel_Wizard(c)
|| (!Chanuser_Hide(u) && !Dark(player)))) {
- format_channel_chat(c, u, player, CB_CHECKQUIET | CB_PRESENCE,
- msg, NULL);
+ channel_send(c, player, CB_CHECKQUIET | CB_PRESENCE | CB_POSE, msg);
}
if (ungag)
CUtype(u) &= ~CU_GAG;
COMMAND(cmd_cemit)
{
- int spflags = !strcmp(cmd->name, "@NSCEMIT") ? PEMIT_SPOOF : 0;
+ int spflags = (!strcmp(cmd->name, "@NSCEMIT")
+ && Can_Nspemit(player) ? PEMIT_SPOOF : 0);
SPOOF(player, cause, sw);
if (SW_ISSET(sw, SWITCH_SILENT))
spflags |= PEMIT_SILENT;
do_chan_desc(player, arg_left, args_right[1]);
else if (SW_ISSET(sw, SWITCH_TITLE))
do_chan_title(player, arg_left, args_right[1]);
+ else if (SW_ISSET(sw, SWITCH_MOGRIFIER))
+ do_chan_set_mogrifier(player, arg_left, args_right[1]);
else if (SW_ISSET(sw, SWITCH_CHOWN))
do_chan_chown(player, arg_left, args_right[1]);
else if (SW_ISSET(sw, SWITCH_WIPE))
return current;
}
+/**
+ * Mogrify a value using u(<mogrifier>/<attrname>,<value>)
+ *
+ * \param mogrifier The object doing the mogrification
+ * \param attrname The attribute on mogrifier to call.
+ * \param channel The active channel. (%1)
+ * \param value The value to mogrify (%0)
+ * \retval Mogrified text.
+ */
+
+char *
+mogrify(dbref mogrifier, char *attrname,
+ dbref player, int numargs, char *argv[], char *orig)
+{
+ static char buff[BUFFER_LEN];
+ const char *wenv[10] = { 0 };
+ int i;
+ buff[0] = '\0';
+ for (i = 0; i < numargs; i++) {
+ wenv[i] = argv[i];
+ }
+
+ if (call_attrib(mogrifier, attrname, wenv, numargs, buff, player, NULL)) {
+ if (buff[0]) {
+ return buff;
+ }
+ }
+
+ snprintf(buff, BUFFER_LEN, "%s", orig);
+
+ return buff;
+}
+
/** Broadcast a message to a channel, using @chatformat if it's
- * available.
+ * available, and mogrifying.
* \param channel pointer to channel to broadcast to.
* \param player message speaker.
* \param flags broadcast flag mask (see CB_* constants in extchat.h)
* \param fmt message format string.
*/
-void WIN32_CDECL
-channel_chat(CHAN *channel, dbref player, int flags,
- const char *message, char type, const char *fmt, ...)
-/* flags: 0x1 = checkquiet, 0x2 = nospoof */
+void
+channel_send(CHAN *channel, dbref player, int flags, const char *origmessage)
{
- va_list args;
-#ifdef HAS_VSNPRINTF
- char tbuf1[BUFFER_LEN];
-#else
- char tbuf1[BUFFER_LEN * 2]; /* Safety margin as per tprintf */
-#endif
+/* flags:
+ * CB_CHECKQUIET CB_NOSPOOF CB_PRESENCE CB_POSE CB_EMIT CB_SPEECH
+ */
+
+ /* These are static only to prevent them from chewing up
+ * time to malloc/free, and chewing up space.
+ */
+ static char channame[BUFFER_LEN];
+ static char title[BUFFER_LEN];
+ static char playername[BUFFER_LEN];
+ static char message[BUFFER_LEN];
+ static char buff[BUFFER_LEN];
+ static char speechtext[BUFFER_LEN];
+
CHANUSER *u;
+ CHANUSER *speaker;
dbref current;
- const char *cname;
- const char *name, *title;
- char ctype[2];
- char ctitle[CU_TITLE_LEN];
+ char *bp;
+ char *blockstr = "";
int na_flags = NA_INTER_LOCK;
const char *someone = "Someone";
+ dbref mogrifier = NOTHING;
+ char *ctype = NULL;
+ char *argv[10];
+ int override_chatformat = 0;
+ memset(argv, 0, sizeof(argv));
- ctype[0] = type;
- ctype[1] = '\0';
-
- /* Make sure we can write to the channel before doing so */
+ /* Make sure we can write to the channel before doing anything */
if (Channel_Disabled(channel))
return;
- va_start(args, fmt);
+ speaker = onchannel(player, channel);
-#ifdef HAS_VSNPRINTF
- (void) vsnprintf(tbuf1, sizeof tbuf1, fmt, args);
-#else
- (void) vsprintf(tbuf1, fmt, args);
-#endif
- va_end(args);
- tbuf1[BUFFER_LEN - 1] = '\0';
+ snprintf(channame, BUFFER_LEN, "<%s>", ChanName(channel));
- cname = ChanName(channel);
- u = onchannel(player, channel);
- strcpy(ctitle, (u && CUtitle(u)) ? CUtitle(u) : "");
+ if (!Channel_NoTitles(channel) && speaker &&
+ CUtitle(speaker) && *CUtitle(speaker)) {
+ snprintf(title, BUFFER_LEN, "%s", CUtitle(speaker));
+ } else {
+ title[0] = '\0';
+ }
- if (!Channel_NoTitles(channel) || !*ctitle)
- title = ctitle;
- else
- title = NULL;
- if (Channel_NoNames(channel))
- name = NULL;
- else
- name = accented_name(player);
- if (!title && !name)
- name = someone;
+ if (Channel_NoNames(channel)) {
+ playername[0] = '\0';
+ } else {
+ snprintf(playername, BUFFER_LEN, "%s", accented_name(player));
+ }
+ if (!title[0] && !playername[0]) {
+ snprintf(playername, BUFFER_LEN, "%s", someone);
+ }
+
+ if (flags & CB_PRESENCE) {
+ ctype = "@";
+ } else if (flags & CB_POSE) {
+ ctype = ":";
+ } else if (flags & CB_SEMIPOSE) {
+ ctype = ";";
+ } else if (flags & CB_EMIT) {
+ ctype = "|";
+ } else {
+ ctype = "\"";
+ }
+
+ snprintf(speechtext, BUFFER_LEN, "says");
+
+ snprintf(message, BUFFER_LEN, "%s", origmessage);
+
+ if (GoodObject(ChanMogrifier(channel))) {
+ if (eval_lock(player, ChanMogrifier(channel), Use_Lock)) {
+ mogrifier = ChanMogrifier(channel);
+
+ argv[0] = ctype;
+ argv[1] = ChanName(channel);
+ argv[2] = message;
+ argv[3] = playername;
+ argv[4] = title;
+
+ blockstr = mogrify(mogrifier, "MOGRIFY`BLOCK", player, 6, argv, "");
+ if (blockstr && *blockstr) {
+ notify(player, blockstr);
+ return;
+ }
+ // Do we override chatformats?
+ if (parse_boolean
+ (mogrify(mogrifier, "MOGRIFY`OVERRIDE", player, 6, argv, ""))) {
+ override_chatformat = 1;
+ }
+
+ argv[1] = ChanName(channel);
+ argv[2] = ctype;
+ argv[3] = message;
+ argv[4] = title;
+ argv[5] = playername;
+
+ argv[0] = channame;
+ snprintf(channame, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`CHANNAME", player, 6, argv,
+ channame));
+
+ argv[0] = title;
+ snprintf(title, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`TITLE", player, 6, argv, title));
+
+ argv[0] = playername;
+ snprintf(playername, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`PLAYERNAME", player, 6, argv,
+ playername));
+
+ if (flags & CB_SPEECH) {
+ argv[0] = speechtext;
+ snprintf(speechtext, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`SPEECHTEXT", player, 6, argv,
+ speechtext));
+ }
+
+ argv[0] = message;
+ snprintf(message, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`MESSAGE", player, 6, argv, message));
+ }
+ }
+
+ bp = buff;
+
+ *bp = '\0';
+
+ if (!(flags & CB_QUIET)) {
+ safe_str(channame, buff, &bp);
+ safe_chr(' ', buff, &bp);
+ }
+
+ if (flags & CB_EMIT) {
+ safe_str(message, buff, &bp);
+ } else {
+ if (!(flags & CB_PRESENCE)) {
+ if (title[0]) {
+ safe_str(title, buff, &bp);
+ safe_chr(' ', buff, &bp);
+ }
+ }
+ safe_str(playername, buff, &bp);
+ switch (flags & CB_TYPE) {
+ case CB_POSE:
+ safe_chr(' ', buff, &bp);
+ case CB_SEMIPOSE:
+ safe_str(message, buff, &bp);
+ break;
+ case CB_SPEECH:
+ safe_format(buff, &bp, " %s, \"%s\"", T(speechtext), message);
+ break;
+ }
+ }
+ *bp = '\0';
- if (Channel_Interact(channel))
+ // @chatformat
+ if (flags & CB_PRESENCE) {
+ snprintf(title, BUFFER_LEN, "%s", message);
+ snprintf(message, BUFFER_LEN, "%s %s", Name(player), title);
+ title[0] = '\0';
+ }
+
+ if (GoodObject(mogrifier)) {
+ argv[0] = ctype;
+ argv[1] = ChanName(channel);
+ argv[2] = message;
+ argv[3] = playername;
+ argv[4] = title;
+ argv[5] = buff;
+ snprintf(buff, BUFFER_LEN, "%s",
+ mogrify(mogrifier, "MOGRIFY`FORMAT", player, 6, argv, buff));
+ }
+
+ if (Channel_Interact(channel)) {
na_flags |= (flags & CB_PRESENCE) ? NA_INTER_PRESENCE : NA_INTER_HEAR;
+ }
+
+ if (!(flags & CB_NOSPOOF)) {
+ na_flags |= NA_SPOOF;
+ }
for (u = ChanUsers(channel); u; u = u->next) {
current = CUdbref(u);
- if (!(((flags & 1) && Chanuser_Quiet(u)) ||
+ if (!(((flags & CB_CHECKQUIET) && Chanuser_Quiet(u)) ||
Chanuser_Gag(u) || (IsPlayer(current) && !Connected(current)))) {
- if (!vmessageformat(current, "CHATFORMAT", player,
- na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF),
- 6, ctype, cname, message, name, title, tbuf1)) {
- notify_anything(player, na_one, ¤t, ns_esnotify,
- na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF),
- tbuf1);
+ if (override_chatformat
+ || !vmessageformat(current, "CHATFORMAT", player,
+ na_flags,
+ 6,
+ ctype,
+ ChanName(channel),
+ message, playername, title, buff)) {
+ notify_anything(player, na_one, ¤t, ns_esnotify, na_flags, buff);
}
}
}
if (ChanBufferQ(channel))
add_to_bufferq(ChanBufferQ(channel), 0,
- (flags & CB_NOSPOOF) ? player : NOTHING, tbuf1);
-}
+ (flags & CB_NOSPOOF) ? player : NOTHING, buff);
+ if (!(flags & CB_PRESENCE) && !speaker) {
+ notify_format(player, T("To channel %s: %s"), ChanName(channel), buff);
+ }
+}
/** Recall past lines from the channel's buffer.
* We try to recall no more lines that are requested by the player,
}
}
-/* msg is a printf-style format that has exactly and only 2 %s specifiers
- in it. */
-static void
-format_channel_chat(CHAN *chan, CHANUSER *u,
- dbref victim, int flags, const char *msg, const char *extra)
-{
- const char *title = NULL;
- char fmtbuff[BUFFER_LEN];
- if (extra && *extra)
- title = extra;
- else if (u && CUtitle(u))
- title = CUtitle(u);
- if (Channel_NoNames(chan)) {
- if (Channel_NoTitles(chan) || !title) {
- channel_chat(chan, victim, flags, msg, '@', ChanName(chan), "Someone");
- snprintf(fmtbuff, BUFFER_LEN, msg, "Someone");
- } else {
- snprintf(fmtbuff, BUFFER_LEN, msg, title);
- }
- } else {
- snprintf(fmtbuff, BUFFER_LEN, msg, Name(victim));
- }
- channel_chat(chan, victim, flags, fmtbuff, '@', "<%s> %s",
- ChanName(chan), fmtbuff);
-}
-
-
/** Evaluate a channel lock with %0 set to the channel name.
* \param c the channel to test.
* \param p the object trying to pass the lock.
global_eval_context.wenv[0] = ChanName(c);
for (n = 1; n < 10; n++)
global_eval_context.wenv[n] = NULL;
- retval = eval_boolexp(p, b, p);
+ retval = eval_boolexp(p, b, p, NULL);
restore_global_env("eval_chan_lock", oldenv);
return retval;
}