/***************************************************************************
* God Wars Mud copyright (C) 1994, 1995, 1996 by Richard Woolcock *
* *
* Legend of Chrystancia copyright (C) 1999, 2000, 2001 by Matthew Little *
* This mud is NOT to be copied in whole or in part, or to be run without *
* the permission of Matthew Little. Nobody else has permission to *
* authorise the use of this code. *
***************************************************************************/
/*
* source file for mxp
*
* Brian Graversen
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
/* telnet negotiating */
const char mxp_will [] = { IAC, WILL, TELOPT_MXP, '\0' };
const char mxp_do [] = { IAC, DO, TELOPT_MXP, '\0' };
const char mxp_dont [] = { IAC, DONT, TELOPT_MXP, '\0' };
/*
* mxp_to_char()
* -------------
*
* When sending MXP messages with this function, you should
* always use <BR> instead of \n\r, since \n\r resets the
* state of MXP. <BR> will do a linebreak just like \n\r,
* but the state is kept.
*
* The following MXP tags are supported, and works well
* in zmud 6.16 and mushclient 3.17. Other clients may
* work, but it's very unlikely.
*
* <B>text</B> : BOLD
* <I>text</I> : ITALIC
* <U>text</U> : UNDERLINE
* <BR> : LINEBREAK (is replaced with \n\r if no MXP)
*
* Some of these more advanced features are also supported
* -------------------------------------------------------
* <A href="URL">text</A> : web hyperlinks.
* <SEND [args]>text</SEND> : mud hyperlinks and menus.
*
*/
void mxp_to_char(CHAR_DATA *ch, char *txt, int mxp_style)
{
char buf[2*MAX_STRING_LENGTH];
int i = 0, j = 0;
if (!ch->desc)
return;
if (USE_MXP(ch))
{
switch(mxp_style)
{
default:
bug("Mxp_to_char: strange style '%d'.", mxp_style);
strcpy(buf, txt);
case MXP_SAFE:
sprintf(buf, "%s%s%s", "\e[0z", txt, "\e[7z");
break;
case MXP_ALL:
/* There is a bug in zmud 6.16 so we can not do the obvious
* here. Instead we'll use this workaround. In the future,
* the bug in zmud might be fixed, and the following line
* can replace everything else.
*
* NOTE: It now works with zmud 6.25 as well... not pretty.
*
* sprintf(buf, "%s%s%s", "\e[1z", txt, "\e[7z");
*
*/
buf[j++] = '\e'; buf[j++] = '['; buf[j++] = '1'; buf[j++] = 'z';
while (txt[i] != '\0')
{
switch(txt[i])
{
default:
buf[j++] = txt[i++];
break;
case '<':
if (!memcmp(&txt[i], "<BR>", strlen("<BR>")))
{
i += strlen("<BR>");
buf[j++] = '\n'; buf[j++] = '\r'; buf[j++] = '\e';
buf[j++] = '['; buf[j++] = '1'; buf[j++] = 'z';
}
else
buf[j++] = txt[i++];
break;
}
}
buf[j++] = '\e'; buf[j++] = '['; buf[j++] = '7'; buf[j++] = 'z';
buf[j] = '\0';
break;
case MXP_NONE:
sprintf(buf, "%s%s", "\e[7z", txt);
break;
}
}
else
{
while(txt[i] != '\0')
{
switch(txt[i])
{
default:
buf[j++] = txt[i++];
break;
case '<':
if (!memcmp(&txt[i], "<B>", strlen("<B>")))
i += strlen("<B>");
else if (!memcmp(&txt[i], "</B>", strlen("</B>")))
i += strlen("</B>");
else if (!memcmp(&txt[i], "<U>", strlen("<U>")))
i += strlen("<U>");
else if (!memcmp(&txt[i], "</U>", strlen("</U>")))
i += strlen("</U>");
else if (!memcmp(&txt[i], "<I>", strlen("<I>")))
i += strlen("<I>");
else if (!memcmp(&txt[i], "</I>", strlen("</I>")))
i += strlen("</I>");
else if (!memcmp(&txt[i], "<BR>", strlen("<BR>")))
{
buf[j++] = '\n'; buf[j++] = '\r';
i += strlen("<BR>");
}
else if (!memcmp(&txt[i], "<SEND", strlen("<SEND")))
{
i += strlen("<SEND");
while(txt[i++] != '>')
;
}
else if (!memcmp(&txt[i], "<A href", strlen("<A href")))
{
i += strlen("<A href");
while(txt[i++] != '>')
;
}
else if (!memcmp(&txt[i], "</SEND>", strlen("</SEND>")))
i += strlen("</SEND>");
else if (!memcmp(&txt[i], "</A>", strlen("</A>")))
i += strlen("</A>");
else
buf[j++] = txt[i++];
break;
}
}
buf[j] = '\0';
}
send_to_char(buf, ch);
}
void mxp_to_cchar(CHAR_DATA *ch, char *txt, int mxp_style)
{
char buf[2*MAX_STRING_LENGTH];
int i = 0, j = 0;
if (!ch->desc)
return;
if (USE_MXP(ch))
{
switch(mxp_style)
{
default:
bug("Mxp_to_char: strange style '%d'.", mxp_style);
strcpy(buf, txt);
case MXP_SAFE:
sprintf(buf, "%s%s%s", "\e[0z", txt, "\e[7z");
break;
case MXP_ALL:
/* There is a bug in zmud 6.16 so we can not do the obvious
* here. Instead we'll use this workaround. In the future,
* the bug in zmud might be fixed, and the following line
* can replace everything else.
*
* NOTE: It now works with zmud 6.25 as well... not pretty.
*
* sprintf(buf, "%s%s%s", "\e[1z", txt, "\e[7z");
*
*/
buf[j++] = '\e'; buf[j++] = '['; buf[j++] = '1'; buf[j++] = 'z';
while (txt[i] != '\0')
{
switch(txt[i])
{
default:
buf[j++] = txt[i++];
break;
case '<':
if (!memcmp(&txt[i], "<BR>", strlen("<BR>")))
{
i += strlen("<BR>");
buf[j++] = '\n'; buf[j++] = '\r'; buf[j++] = '\e';
buf[j++] = '['; buf[j++] = '1'; buf[j++] = 'z';
}
else
buf[j++] = txt[i++];
break;
}
}
buf[j++] = '\e'; buf[j++] = '['; buf[j++] = '7'; buf[j++] = 'z';
buf[j] = '\0';
break;
case MXP_NONE:
sprintf(buf, "%s%s", "\e[7z", txt);
break;
}
}
else
{
while(txt[i] != '\0')
{
switch(txt[i])
{
default:
buf[j++] = txt[i++];
break;
case '<':
if (!memcmp(&txt[i], "<B>", strlen("<B>")))
i += strlen("<B>");
else if (!memcmp(&txt[i], "</B>", strlen("</B>")))
i += strlen("</B>");
else if (!memcmp(&txt[i], "<U>", strlen("<U>")))
i += strlen("<U>");
else if (!memcmp(&txt[i], "</U>", strlen("</U>")))
i += strlen("</U>");
else if (!memcmp(&txt[i], "<I>", strlen("<I>")))
i += strlen("<I>");
else if (!memcmp(&txt[i], "</I>", strlen("</I>")))
i += strlen("</I>");
else if (!memcmp(&txt[i], "<BR>", strlen("<BR>")))
{
buf[j++] = '\n'; buf[j++] = '\r';
i += strlen("<BR>");
}
else if (!memcmp(&txt[i], "<SEND", strlen("<SEND")))
{
i += strlen("<SEND");
while(txt[i++] != '>')
;
}
else if (!memcmp(&txt[i], "<A href", strlen("<A href")))
{
i += strlen("<A href");
while(txt[i++] != '>')
;
}
else if (!memcmp(&txt[i], "</SEND>", strlen("</SEND>")))
i += strlen("</SEND>");
else if (!memcmp(&txt[i], "</A>", strlen("</A>")))
i += strlen("</A>");
else
buf[j++] = txt[i++];
break;
}
}
buf[j] = '\0';
}
cent_to_char(buf, ch);
}
void init_mxp(DESCRIPTOR_DATA *d)
{
const char enable_mxp[] = { IAC, SB, TELOPT_MXP, IAC, SE, '\0' };
write_to_buffer(d, enable_mxp, 0);
write_to_buffer(d, "\e[7z", 0);
d->mxp = TRUE;
}
void shutdown_mxp(DESCRIPTOR_DATA *d)
{
d->mxp = FALSE;
}
void do_mxp(CHAR_DATA *ch, char *argument)
{
if (!ch->desc)
return;
if (!ch->desc->mxp)
{
send_to_char("Sorry, your client does not support MXP.\n\r", ch);
return;
}
if (IS_SET(ch->extra2, PLR_MXP))
{
REMOVE_BIT(ch->extra2, PLR_MXP);
send_to_char("MXP has been disabled.\n\r", ch);
}
else
{
SET_BIT(ch->extra2, PLR_MXP);
send_to_char("MXP has been enabled.\n\r", ch);
}
}
void do_mudvote(CHAR_DATA *ch, char *argument)
{
mxp_to_char(ch, "<A href=\"http://www.mudconnect.com/cgi-bin/vote_rank.cgi?mud=YOUR+MUD+NAME\">Vote For Us at Mudconnector</A>\n\r", MXP_ALL);
}
void do_mxptest(CHAR_DATA *ch, char *argument)
{
mxp_to_char(ch, "<B>This is bold</B>\n\r", MXP_ALL);
mxp_to_char(ch, "<I>This is italic</I>\n\r", MXP_ALL);
mxp_to_char(ch, "<SEND href=\"say test\">click me</SEND>\n\r", MXP_ALL);
mxp_to_char(ch, "<A href=\"http://groups.yahoo.com/group/Chrystancia\">Mailing List</A>\n\r", MXP_ALL);
mxp_to_char(ch, "<A href=\"http://www.soton.ac.uk/~gc5/dirs.htm\">Quest Locations</A>\n\r", MXP_ALL);
mxp_to_char(ch, "<SEND href=\"say i clicked it|smile|look\" hint=\"Click to see the menu|First entry|Second entry|Third entry\">A Menu</SEND>", MXP_ALL);
}
void do_showmxp(CHAR_DATA *ch, char *argument)
{
DESCRIPTOR_DATA *d;
CHAR_DATA *gch;
char buf[MAX_STRING_LENGTH];
int count1 = 0;
int count2 = 0;
if (IS_NPC(ch)) return;
for (d = first_descriptor; d != NULL; d = d->next)
{
if (d->connected != CON_PLAYING) continue;
if (d->character != NULL) gch = d->character;
else continue;
if USE_MXP(gch)
{
sprintf(buf, "%-15s uses MXP\n\r", gch->name);
count1++;
}
else
{
sprintf(buf,"%-15s Does not use MXP.\n\r", gch->name);
count2++;
}
send_to_char(buf, ch);
}
sprintf(buf,"\n\r%d out of %d players uses MXP\n\r",
count1, count2 + count1);
send_to_char(buf, ch);
return;
}