05 Sep, 2007, David Haley wrote in the 21st comment:
Votes: 0
Sure, why not… What exactly do I need to do to test this out?

On a side note, I never did really like how the SMAUG base chunks out data like it does. It makes more sense to me to just send as much as possible as quickly as you can, and if the socket is going to block, you wait till next time to not hold up the whole system.
05 Sep, 2007, Scandum wrote in the 22nd comment:
Votes: 0
Zeno said:
Not sure if WinTin++ is fine to use.

But I tested it out. It still happens, and it seems to be worse. Instead of a 16sec delay like "normal", the delay lasts about 42sec. Another strange thing is that it stops at a different place.

As for on AFKMUD, I don't notice much of a difference. The delay is still there, but it doesn't seem to be any longer.

WinTin++ is about 2 to 3 times slower (which generally isn't noticeable) so that sounds about right. I'd guess something in the mccp handling clogs up the decompression.
07 Sep, 2007, Zeno wrote in the 23rd comment:
Votes: 0
David: No need to test it, I had a friend in FL test it. So yeah, it's not my network.
07 Sep, 2007, kiasyn wrote in the 24th comment:
Votes: 0
Zeno said:
David: No need to test it, I had a friend in FL test it. So yeah, it's not my network.


and if you have the same isp and thats the cause…
07 Sep, 2007, Zeno wrote in the 25th comment:
Votes: 0
Nope, different ISP of course.
18 Dec, 2012, Hades_Kane wrote in the 26th comment:
Votes: 0
So, I've been thinking about adding this.

I know I'm resurrecting this, but it would seem to be the most valid place to continue discussion about this.

Five years later, has anyone's opinions of the protocol changed? What are other's feelings on whether it is good/useful/worth putting in?

I've also been surprised by the lack of a dedicate MCCP alone snippet. I've run across two (specifically the two linked from http://tintin.sourceforge.net/mccp/), but anything I've ran across is bundled in with a ton of other protocols. Likewise, the code referenced in the article (and was quoted in another post by Rarva.Riendf) lack any real instructions on installing that alone. I'm not a total code noob, but stuff like this is foreign to a lot of us, and it helps to have some stuff spelled out. If I decide to implement it and do it correctly, I may see about releasing something here that has it as a stand-a-lone.

Anyhow, just looking for some input :)
18 Dec, 2012, Rarva.Riendf wrote in the 27th comment:
Votes: 0
Well let me try to help :)

I put all my code cause the core is old and use \r\n instead of \n\r (ans last time I tried to change that, let say it opened a can of worrns I promptly closed)
but you just have to look at when
compresstart
compressend
and
writecompressed
appear, and where to free memory when you close the socket.
I really dont remember how I installed it..probably looked at another mud codebase that had it installed already.
But with the code I gave you and that, it should be easily be installed in yours provided it is a rom based one. (notive I save mccp status in the player, to allow them to enable/disable it)

basically only a few lines of code is needed to implement mccp outside the mccp class itself.

in comm.c

bool_t write_to_descriptor(DESCRIPTOR_DATA *d, char *txt, int length) {
if (length <= 0)
length = strlen(txt);

if (d->mccp)
return write_compressed(d, txt, length);

return write_to_descriptor_uncompressed(d->descriptor, txt, length);
}

void read_from_buffer(DESCRIPTOR_DATA *d) {
/*
* Hold horses if pending command already.
*/
if (d->incomm[0] != '\0')
return;

int i, k;
/*
* Look for at least one new line.
*/
for (i = 0;d->inbuf[i] != '\n' && d->inbuf[i] != '\r';i ++) {
if (d->inbuf[i] == '\0')
return;
}

/*
* Canonical input processing.
*/
for (i = 0, k = 0;d->inbuf[i] != '\n' && d->inbuf[i] != '\r';i ++) {
if (k >= MAX_INPUT_LENGTH - 2) {
write_to_descriptor(d, "Line too long.\n\r", 0);

/* skip the rest of the line */
for (;d->inbuf[i] != '\0';i ++) {
if (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
break;
}
d->inbuf[i] = '\n';
d->inbuf[i + 1] = '\0';
break;
}

if (d->inbuf[i] == (signed char)IAC) {
if ( !memcmp( &d->inbuf[i], mccp_do, strlen(mccp_do))) {
i += strlen(mccp_do) - 1;
compressStart(d);
}
else if ( !memcmp( &d->inbuf[i], mccp_dont, strlen(mccp_dont))) {
i += strlen(mccp_dont) - 1;
compressEnd(d);
}
}
else if (d->inbuf[i] == '\b' && k > 0)
–k;
else if (xisascii(d->inbuf[i]) && xisprint(d->inbuf[i]))
d->incomm[k ++] = d->inbuf[i];
}

/*
* Finish off the line.
*/
if (k == 0)
d->incomm[k ++] = ' ';
d->incomm[k] = '\0';

/*
* Deal with bozos with #repeat 1000 …
*/

if (k> 1 || d->incomm[0] == '!') {
if (d->incomm[0] != '!' && str_cmp(d->incomm, d->inlast)) {
d->repeat = 0;
}
else {
if ( ++d->repeat >= 25) {
sprintf(log_buf, "%s input spamming!", d->host);
log_string(log_buf);

d->repeat = 0;
write_to_descriptor(d, "\n\r*** PUT A LID ON IT!!! ***\n\r", 0);
/*
strcpy( d->incomm, "quit" );
*/
}
}
}

/*
* Do '!' substitution.
*/
if (d->incomm[0] == '!' && d->incomm[1] != '!')
strcpy(d->incomm, d->inlast);
else
strcpy(d->inlast, d->incomm);

/*
* Shift the input buffer.
*/
while (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
i ++;
for (k = 0;(d->inbuf[k] = d->inbuf[i + k]) != '\0';k ++)
;
}

bool_t check_reconnect(DESCRIPTOR_DATA *d, char *name, bool_t fConn) {
CHAR_DATA *ch, *ch_next, *tempChar;
for (ch = char_list;ch ;ch = ch_next) {
ch_next = ch->next;
if (!ch->valid || IS_NPC(ch) || ( fConn && ch->desc) || str_cmp(d->character->charname, ch->charname))
continue;
if ( !fConn)
replace_string(&d->character->pcdata->pwd,ch->pcdata->pwd);
else {
tempChar = d->character;
extract_char(d->character, TRUE, CHAR_RETURN_IGNORED);
free_char(tempChar);
d->character = ch;
ch->desc = d;
ch->timer = 0;
send_to_char("Reconnecting.\n\r", ch);
act("$n has reconnected.", ch, NULL, NULL, TO_ROOM );

char buf[MAX_STRING_LENGTH];
sprintf(log_buf, "%s@%s reconnected.", ch->charname, d->host);
log_string(log_buf);
sprintf(buf, "%s@%s has reconnected.", ch->charname, d->host);
if ( !IS_IMP(ch))
info(buf, LEVEL_SENIOR, INFO_PLR_CONNECT);
d->connected = !ch->in_room ? CON_GET_REMORT : CON_PLAYING;
compressStart(d);
MXPSendTag( d, "<VERSION>" );
}
return TRUE;
}
return FALSE;
}

void close_socket(DESCRIPTOR_DATA *dclose) {
if (!dclose)
return;
if (dclose->outtop > 0)
process_output(dclose, FALSE );

if (dclose->snoop_by )
write_to_buffer(dclose->snoop_by, "Your victim has left the realm.\n\r");

DESCRIPTOR_DATA *d;
for (d = descriptor_list;d ;d = d->next) {
if (d->snoop_by == dclose)
d->snoop_by = NULL;
}

CHAR_DATA *ch = dclose->character;
if (ch) {
bool_t isSwitched = dclose->original ? TRUE : FALSE;
if (isSwitched)
do_return(ch, "");
sprintf(log_buf, "Closing link to %s: address %p", ch->charname, ch);
log_string(log_buf);
if (dclose->connected == CON_PLAYING || dclose->connected == CON_REDITOR || dclose->connected == CON_AEDITOR
|| dclose->connected == CON_MEDITOR || dclose->connected == CON_MPEDITOR || dclose->connected
== CON_HEDITOR || dclose->connected == CON_OEDITOR || dclose->connected == CON_GET_REMORT
|| dclose->connected == CON_SUB_CLASS || dclose->connected == CON_SUB_CLASS2
|| dclose->connected == CON_REMORT) {
act("$n has lost $s link.", ch, NULL, NULL, TO_ROOM );
ch->desc = NULL;
if (isSwitched)
dclose->character->desc = NULL;
}
else {
free_char( dclose->original ? dclose->original : dclose->character );
}
}

if ( dclose == descriptor_list ) {
descriptor_list = descriptor_list->next;
}
else {
for ( d = descriptor_list; d && (d->next != dclose); d = d->next )
;
if ( d )
d->next = dclose->next;
else
bug( "Close_socket: dclose not found.", 0 );
}
compressEnd(dclose);
close( dclose->descriptor );
free_descriptor(dclose);
}

in recycle.c

void free_descriptor(DESCRIPTOR_DATA *d) {
if ( !d)
return;
log_param("descriptor memory freed: address %p", d);
if (!compressEnd(d))
compressEnd(d);
ProtocolDestroy( d->pProtocol );
free_string( &d->host);
free_string( &d->showstr_head);
if (d->pString && *d->pString)
free_string( &*d->pString);
free_string( &d->outbuf);
if (d == descIt) {//bloody hack to solve a bug in nanny
free(d);
descIt = NULL;
}
else if (d == descItNext) {
descItNext = d->next;
free(d);
}
else
free(d);
d = NULL;
}


in nanny
case CON_GET_OLD_PASSWORD:
write_to_buffer(d, "\n\r");
if (str_cmp(argument, ch->pcdata->pwd)) {
//crypt version if (str_cmp(crypt(argument,ch->charname), ch->pcdata->pwd)) {
sprintf(buf, "Wrong Password: %s@%s\n\r", ch->charname, d->host);
info(buf, LEVEL_SENIOR, INFO_BUG);
sprintf(buf, "Typed: %s\n\r", argument);
log_param("Wrong password for %s: Typed: %s\n\r", ch->charname, argument);
info(buf, LEVEL_IMP, INFO_BUG);
write_to_buffer(d, "Wrong password.\n\r");
if (d->character) {
extract_char(d->character, TRUE, CHAR_RETURN_LIST);
free_char(ch);
}
close_socket(d);
return;
}

write_to_buffer(d, echo_on_str);

if (check_playing(d, ch->charname))
return;

if (check_reconnect(d, ch->charname, TRUE))
return;

sprintf(log_buf, "%s@%s has connected.", ch->charname, d->host);
sort_connected(ch);
log_string(log_buf);

//we store the host in pcdata here cause in case of someone going linkdead we lose the descriptor
//and so cannot save the last ip he connected from.
if (ch->desc && ch->desc->host && ch->pcdata)
replace_string( &ch->pcdata->host, ch->desc->host);

connections ++;

if ( !IS_IMP(ch))
info(log_buf, LEVEL_SENIOR, INFO_PLR_CONNECT);

if (IS_IMMORTAL(ch)) {
send_to_char(get_acolor_ch(ch, C_GRN), ch);
do_help(ch, "imotd");
send_to_char(get_color_ch(ch, COL_NORM), ch);
d->connected = CON_READ_IMOTD;

}
if ( !IS_SET(ch->config, CONF_PKILL) && ch->level >= LEVEL_PK) {
do_help(ch, "pkill");
write_to_buffer(d, "\n\rWill you be PK or NPK? ");
d->connected = CON_PKILL;
}
else {
send_to_char(get_acolor_ch(ch, C_YEL), ch);
do_help(ch, "motd");
send_to_char(get_color_ch(ch, COL_NORM), ch);
d->connected = CON_READ_MOTD;
}
compressStart(ch->desc);
break;


in recycle.c
void free_descriptor(DESCRIPTOR_DATA *d) {
if ( !d)
return;
log_param("descriptor memory freed: address %p", d);
if (!compressEnd(d))
compressEnd(d);
ProtocolDestroy( d->pProtocol );
free_string( &d->host);
free_string( &d->showstr_head);
if (d->pString && *d->pString)
free_string( &*d->pString);
free_string( &d->outbuf);
if (d == descIt) {//bloody hack to solve a bug in nanny
free(d);
descIt = NULL;
}
else if (d == descItNext) {
descItNext = d->next;
free(d);
}
else
free(d);
d = NULL;
}


and of course in protocol.c you have to activate it since you now use Kavir snippet
static void CompressStart(descriptor_t *apDescriptor) {
/* If your mud uses MCCP (Mud Client Compression Protocol), you need to
* call whatever function normally starts compression from here - the
* ReportBug() call should then be deleted.
*
* Otherwise you can just ignore this function.
*/
if (apDescriptor->character && IS_SET(apDescriptor->character->config, CONF_MCCP))
compressStart(apDescriptor);
}

static void CompressEnd(descriptor_t *apDescriptor) {
/* If your mud uses MCCP (Mud Client Compression Protocol), you need to
* call whatever function normally starts compression from here - the
* ReportBug() call should then be deleted.
*
* Otherwise you can just ignore this function.
*/
if ((apDescriptor->character && IS_SET(apDescriptor->character->config, CONF_MCCP)) || apDescriptor->mccp)
compressEnd(apDescriptor);
}
20.0/27