tf5-5.0beta8/.git/
tf5-5.0beta8/.git/info/
tf5-5.0beta8/.git/logs/
tf5-5.0beta8/.git/logs/refs/heads/
tf5-5.0beta8/.git/objects/00/
tf5-5.0beta8/.git/objects/01/
tf5-5.0beta8/.git/objects/04/
tf5-5.0beta8/.git/objects/05/
tf5-5.0beta8/.git/objects/07/
tf5-5.0beta8/.git/objects/09/
tf5-5.0beta8/.git/objects/0a/
tf5-5.0beta8/.git/objects/0c/
tf5-5.0beta8/.git/objects/0e/
tf5-5.0beta8/.git/objects/12/
tf5-5.0beta8/.git/objects/13/
tf5-5.0beta8/.git/objects/14/
tf5-5.0beta8/.git/objects/16/
tf5-5.0beta8/.git/objects/17/
tf5-5.0beta8/.git/objects/19/
tf5-5.0beta8/.git/objects/1c/
tf5-5.0beta8/.git/objects/1d/
tf5-5.0beta8/.git/objects/1e/
tf5-5.0beta8/.git/objects/1f/
tf5-5.0beta8/.git/objects/20/
tf5-5.0beta8/.git/objects/21/
tf5-5.0beta8/.git/objects/23/
tf5-5.0beta8/.git/objects/27/
tf5-5.0beta8/.git/objects/29/
tf5-5.0beta8/.git/objects/2a/
tf5-5.0beta8/.git/objects/2b/
tf5-5.0beta8/.git/objects/2f/
tf5-5.0beta8/.git/objects/30/
tf5-5.0beta8/.git/objects/33/
tf5-5.0beta8/.git/objects/34/
tf5-5.0beta8/.git/objects/35/
tf5-5.0beta8/.git/objects/39/
tf5-5.0beta8/.git/objects/3c/
tf5-5.0beta8/.git/objects/3d/
tf5-5.0beta8/.git/objects/3f/
tf5-5.0beta8/.git/objects/40/
tf5-5.0beta8/.git/objects/41/
tf5-5.0beta8/.git/objects/42/
tf5-5.0beta8/.git/objects/44/
tf5-5.0beta8/.git/objects/46/
tf5-5.0beta8/.git/objects/47/
tf5-5.0beta8/.git/objects/48/
tf5-5.0beta8/.git/objects/4a/
tf5-5.0beta8/.git/objects/4d/
tf5-5.0beta8/.git/objects/4f/
tf5-5.0beta8/.git/objects/53/
tf5-5.0beta8/.git/objects/54/
tf5-5.0beta8/.git/objects/58/
tf5-5.0beta8/.git/objects/5b/
tf5-5.0beta8/.git/objects/5c/
tf5-5.0beta8/.git/objects/5e/
tf5-5.0beta8/.git/objects/5f/
tf5-5.0beta8/.git/objects/60/
tf5-5.0beta8/.git/objects/61/
tf5-5.0beta8/.git/objects/62/
tf5-5.0beta8/.git/objects/63/
tf5-5.0beta8/.git/objects/66/
tf5-5.0beta8/.git/objects/67/
tf5-5.0beta8/.git/objects/6c/
tf5-5.0beta8/.git/objects/6e/
tf5-5.0beta8/.git/objects/72/
tf5-5.0beta8/.git/objects/73/
tf5-5.0beta8/.git/objects/75/
tf5-5.0beta8/.git/objects/77/
tf5-5.0beta8/.git/objects/7a/
tf5-5.0beta8/.git/objects/7b/
tf5-5.0beta8/.git/objects/7c/
tf5-5.0beta8/.git/objects/7e/
tf5-5.0beta8/.git/objects/7f/
tf5-5.0beta8/.git/objects/81/
tf5-5.0beta8/.git/objects/84/
tf5-5.0beta8/.git/objects/86/
tf5-5.0beta8/.git/objects/87/
tf5-5.0beta8/.git/objects/88/
tf5-5.0beta8/.git/objects/8b/
tf5-5.0beta8/.git/objects/8c/
tf5-5.0beta8/.git/objects/8f/
tf5-5.0beta8/.git/objects/91/
tf5-5.0beta8/.git/objects/93/
tf5-5.0beta8/.git/objects/96/
tf5-5.0beta8/.git/objects/97/
tf5-5.0beta8/.git/objects/99/
tf5-5.0beta8/.git/objects/9a/
tf5-5.0beta8/.git/objects/9b/
tf5-5.0beta8/.git/objects/9c/
tf5-5.0beta8/.git/objects/9d/
tf5-5.0beta8/.git/objects/9e/
tf5-5.0beta8/.git/objects/a1/
tf5-5.0beta8/.git/objects/a3/
tf5-5.0beta8/.git/objects/a4/
tf5-5.0beta8/.git/objects/a6/
tf5-5.0beta8/.git/objects/a7/
tf5-5.0beta8/.git/objects/a8/
tf5-5.0beta8/.git/objects/a9/
tf5-5.0beta8/.git/objects/ab/
tf5-5.0beta8/.git/objects/ac/
tf5-5.0beta8/.git/objects/ae/
tf5-5.0beta8/.git/objects/b1/
tf5-5.0beta8/.git/objects/b2/
tf5-5.0beta8/.git/objects/b3/
tf5-5.0beta8/.git/objects/b7/
tf5-5.0beta8/.git/objects/b9/
tf5-5.0beta8/.git/objects/bb/
tf5-5.0beta8/.git/objects/bc/
tf5-5.0beta8/.git/objects/bd/
tf5-5.0beta8/.git/objects/bf/
tf5-5.0beta8/.git/objects/c0/
tf5-5.0beta8/.git/objects/c1/
tf5-5.0beta8/.git/objects/c2/
tf5-5.0beta8/.git/objects/c3/
tf5-5.0beta8/.git/objects/c5/
tf5-5.0beta8/.git/objects/c7/
tf5-5.0beta8/.git/objects/ca/
tf5-5.0beta8/.git/objects/ce/
tf5-5.0beta8/.git/objects/d1/
tf5-5.0beta8/.git/objects/d3/
tf5-5.0beta8/.git/objects/d4/
tf5-5.0beta8/.git/objects/d5/
tf5-5.0beta8/.git/objects/d8/
tf5-5.0beta8/.git/objects/d9/
tf5-5.0beta8/.git/objects/dc/
tf5-5.0beta8/.git/objects/dd/
tf5-5.0beta8/.git/objects/e1/
tf5-5.0beta8/.git/objects/e4/
tf5-5.0beta8/.git/objects/e5/
tf5-5.0beta8/.git/objects/e6/
tf5-5.0beta8/.git/objects/e7/
tf5-5.0beta8/.git/objects/e8/
tf5-5.0beta8/.git/objects/ea/
tf5-5.0beta8/.git/objects/eb/
tf5-5.0beta8/.git/objects/ed/
tf5-5.0beta8/.git/objects/ee/
tf5-5.0beta8/.git/objects/ef/
tf5-5.0beta8/.git/objects/f0/
tf5-5.0beta8/.git/objects/f4/
tf5-5.0beta8/.git/objects/f5/
tf5-5.0beta8/.git/objects/f6/
tf5-5.0beta8/.git/objects/f8/
tf5-5.0beta8/.git/objects/f9/
tf5-5.0beta8/.git/objects/fa/
tf5-5.0beta8/.git/objects/fb/
tf5-5.0beta8/.git/objects/fc/
tf5-5.0beta8/.git/objects/fd/
tf5-5.0beta8/.git/refs/heads/
tf5-5.0beta8/.git/refs/tags/
tf5-5.0beta8/autom4te.cache/
tf5-5.0beta8/macos/
tf5-5.0beta8/unix/
tf5-5.0beta8/win32/
#include "tfconfig.h"
#include "port.h"
#include "tf.h"
#include "msdp.h"
#include "telopt.h"
#include "search.h"
#include "world.h"
#include "history.h"
#include "tfio.h"
#include "socket.h"
#include "msdp-tok.h"

#define MSDP_VERBOSE	1
#define MSDP_LOOP		2

struct _msdp_commands {
	const char * cmd;
	int id;
	int flags;
};

static const struct _msdp_commands msdp_commands[] = {
	{ "LIST", 1, 0 },
	{ "GET", 2, 0 },
	{ "REPORT", 3, 0 },
};

conString * msdp_encode(const char *);

int send_raw(conString *, const char * world);

struct Value *handle_msdp_command(String * args, int offset) {
	// const char buf[] = "NAME=\"DAN\" ROOM=[ NAME=\"The void\" COORDINATES=[ X=\"0\" Y=\"0\" Z=\"0\" ] ITEMS={ \"FOO\" \"BAR\" \"BAZ\" } ] HP=\"32\"";
	// const char buf[] = "TEST={ A B \"C D\" } FOO=BAR";
	STATIC_BUFFER(buf);
	Stringtrunc(buf, 0);
	SStringocat(buf, CS(args), offset);
	conString * encoded = msdp_encode(buf->data);
	if (msdp_dbg & MSDP_LOOP) {
		recv_msdp_sb(encoded->data+2, encoded->len-2);
	} else {
		send_raw(encoded, 0); // fixme handle world settings later
	}

	return newint(0);
}



conString * msdp_encode(const char * cmd) {
	STATIC_BUFFER(buf);
	Stringtrunc(buf, 0);
	Stringadd(buf, TN_IAC);
	Stringadd(buf, TN_SB);
	Stringadd(buf, TN_MSDP);
	const char ** tokens;
	const char ** r;
	int array_depth=0;
	tokens=msdp_tok(cmd);
	int state=MSDP_VAR;
	for(r=tokens; *r; r++) {
		const char * c=*r;
		if (c[1]==0) { // single character, []{}=
			switch(c[0]) {
			case '[': Stringadd(buf, MSDP_TABLE_OPEN); state=MSDP_VAR; continue;
			case ']': Stringadd(buf, MSDP_TABLE_CLOSE); state=MSDP_VAR; continue;
			case '{': Stringadd(buf, MSDP_ARRAY_OPEN); state=MSDP_VAR; array_depth++; continue;
			case '}': Stringadd(buf, MSDP_ARRAY_CLOSE); state=MSDP_VAR; if (array_depth) array_depth--; continue;
			case '=': Stringadd(buf, MSDP_VAL); state=MSDP_VAL; continue;
			case ' ': continue; // just eat spaces?
			default: break; // single char identifier, fallthrough
			}
		}
		if (state==MSDP_VAR)
			Stringadd(buf, MSDP_VAR);
		else
			state=MSDP_VAR;
		if (c[0] == '"' && c[strlen(c)-1]=='"')
			Stringncat(buf, c+1, strlen(c)-2);
		else
			Stringcat(buf, c);
	}
	msdp_tok_free(tokens);

	// and close it
	Stringadd(buf, TN_IAC);
	Stringadd(buf, TN_SE);

	return CS(buf);
}


int update_msdp_value(conString * name, conString * value) {
	int result;
	STATIC_BUFFER(trig);
	String * old_incoming_text;

	old_incoming_text = incoming_text;

	Stringcpy(trig, "MSDP ");
	SStringocat(trig, name, 6);
	Stringadd(trig, ' ');
	SStringcat(trig, value);

	incoming_text = trig;
	result = find_and_run_matches(NULL, -1, &incoming_text, xworld(),
		TRUE, 0);

	incoming_text = old_incoming_text;

	do_set(name->data, hash_string(name->data),
		value, 0, 0, 0);


	return result;
}

int recv_msdp_sb(const char *p, int olen) {
	STATIC_BUFFER(path);
	STATIC_BUFFER(value);
	STATIC_BUFFER(test);
	int namestack[10];
	int namepos=0;
	const char * pend=p+olen;
	int ret=0;
	int namedepth=0;
	int t;

#define NPUSH(x)	do { namestack[namepos++]=namedepth; namedepth=x; } while (0)
#define NPOP()		do { if (namepos) namedepth=namestack[--namepos]; } while (0)

	Stringcpy(test, "% MSDP recv ");
	Stringcpy(path, "MSDP");
	int setvalue=0;

	/* start with TN_MSDP */
	if (*p && *p == TN_MSDP) {
		int len;
		*p++;
		const char *c;
		int t;

		while (p<pend) {
			switch(*p) {
			case MSDP_VAR:
				c=p+1;
				while(c<pend && *c>MSDP_ARRAY_CLOSE && *c!=TN_IAC)
					c++;

				if (setvalue) {
					Sappendf(test, " Set %s to %s ", path->data,
							value->data);
					update_msdp_value(CS(path), CS(value));
					setvalue=0;
				}
				Stringtrunc(value, 0);
				Stringtrunc(path, namedepth + 4);
				Stringcat(path, "__");
				Stringncat(path, p+1, c-p-1);
				Stringadd(test, ' ');
				SStringcat(test, CS(path));
				p=c;
				break;


			case MSDP_VAL:
				Stringcat(test, "=");
				c=p+1;
				while(c<pend && *c>MSDP_ARRAY_CLOSE && *c!=TN_IAC)
					c++;

				if (c-p-1 > 0) {
					if (!setvalue) {
						t=0;
						Stringncpy(value, p+1, c-p-1);
						setvalue++;
					} else {
						t=value->len+1;
						Stringadd(value, ' ');
						Stringncat(value, p+1, c-p-1);
					}
					SStringocat(test, CS(value), t);
					Stringcat(test, " ");
				}
				p=c;
				break;
			case MSDP_TABLE_OPEN:
				Stringcat(test, " ["); p++;
				NPUSH(path->len-4);
				break;
			case MSDP_TABLE_CLOSE:
				Stringcat(test, "] "); p++;
				NPOP();
				break;
			case MSDP_ARRAY_OPEN:
				Stringcat(test, " {"); p++; break;
			case MSDP_ARRAY_CLOSE:
				Stringcat(test, "} "); p++; break;
			case TN_IAC:
				if (p[1] == TN_SE)
					p=pend;
				else
					p++;
				break;
			default:
				p++;
			}
		}
	} else {
		ret=-1;
	}
	if (setvalue) {
		Sappendf(test, " Set %s to %s ", path->data,
				value->data);
		update_msdp_value(CS(path), CS(value));
		setvalue=0;
	}

	if (msdp_dbg & MSDP_VERBOSE)
		tfputline(CS(test), tfout);

	return ret;
}