/*************************************************************************** * Mud Telopt Handler 1.4 by Igor van den Hoven. 10 Jun 2011 * ***************************************************************************/ #include "mud.h" #include "telnet.h" // Set table size and check for errors. Call once at startup. void init_msdp_table(void) { int index; for (index = 0 ; *msdp_table[index].name ; index++) { if (strcmp(msdp_table[index].name, msdp_table[index+1].name) > 0) { if (*msdp_table[index+1].name) { log_printf("init_msdp_table: Improperly sorted variable: %s.", msdp_table[index]); } } } mud->msdp_table_size = index; } // Binary search on the msdp_table. int msdp_find(char *var) { int val, bot, top, srt; bot = 0; top = mud->msdp_table_size - 1; val = top / 2; while (bot <= top) { srt = strcmp(var, msdp_table[val].name); if (srt < 0) { top = val - 1; } else if (srt > 0) { bot = val + 1; } else { return val; } val = bot + (top - bot) / 2; } return -1; } // Update a variable and queue it if it's being reported. void msdp_update_var(DESCRIPTOR_DATA *d, char *var, char *fmt, ...) { char buf[MAX_STRING_LENGTH]; int index; va_list args; if (d->msdp_data == NULL) { return; } index = msdp_find(var); if (index == -1) { log_printf("msdp_update_var: Unknown variable: %s.", var); return; } va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); if (strcmp(d->msdp_data[index]->value, buf)) { if (HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_REPORTED)) { SET_BIT(d->msdp_data[index]->flags, MSDP_FLAG_UPDATED); SET_BIT(d->comm_flags, COMM_FLAG_MSDPUPDATE); } RESTRING(d->msdp_data[index]->value, buf); } } // Update a variable and send it instantly. void msdp_update_var_instant(DESCRIPTOR_DATA *d, char *var, char *fmt, ...) { char buf[MAX_STRING_LENGTH]; int index; va_list args; if (d->msdp_data == NULL) { return; } index = msdp_find(var); if (index == -1) { log_printf("msdp_update_var_instant: Unknown variable: %s.", var); return; } va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); if (HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_REPORTED)) { descriptor_printf(d, "%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_MSDP, MSDP_VAR, msdp_table[index].name, MSDP_VAL, buf, IAC, SE); } if (strcmp(d->msdp_data[index]->value, buf)) { RESTRING(d->msdp_data[index]->value, buf); } } // Send all reported variables that have been updated. void msdp_send_update(DESCRIPTOR_DATA *d) { char buf[MAX_STRING_LENGTH]; int index, size; if (d->msdp_data == NULL) { return; } size = sprintf(buf, "%c%c%c", IAC, SB, TELOPT_MSDP); for (index = 0 ; index < mud->msdp_table_size ; index++) { if (HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_UPDATED)) { size += cat_sprintf(buf, "%c%s%c%s", MSDP_VAR, msdp_table[index].name, MSDP_VAL, d->msdp_data[index]->value); DEL_BIT(d->msdp_data[index]->flags, MSDP_FLAG_UPDATED); } if (size > MAX_STRING_LENGTH - MAX_INPUT_LENGTH) { break; } } cat_sprintf(buf, "%c%c", IAC, SE); descriptor_printf(d, "%s", buf); DEL_BIT(d->comm_flags, COMM_FLAG_MSDPUPDATE); } char *msdp_get_var(DESCRIPTOR_DATA *d, char *var) { int index; if (d->msdp_data == NULL) { return NULL; } index = msdp_find(var); if (index == -1) { log_printf("msdp_get_var: Unknown variable: %s.", var); return NULL; } return d->msdp_data[index]->value; } void process_msdp_varval( DESCRIPTOR_DATA *d, char *var, char *val ) { int var_index, val_index; if (d->msdp_data == NULL) { return; } var_index = msdp_find(var); if (var_index == -1) { return; } if (HAS_BIT(msdp_table[var_index].flags, MSDP_FLAG_CONFIGURABLE)) { RESTRING(d->msdp_data[var_index]->value, val); if (msdp_table[var_index].fun) { msdp_table[var_index].fun(d, var_index); } return; } // Commands only take variables as arguments. if (HAS_BIT(msdp_table[var_index].flags, MSDP_FLAG_COMMAND)) { val_index = msdp_find(val); if (val_index == -1) { return; } if (msdp_table[var_index].fun) { msdp_table[var_index].fun(d, val_index); } return; } } void msdp_command_list(DESCRIPTOR_DATA *d, int index) { int flag; char buf[MAX_STRING_LENGTH]; if (!HAS_BIT(msdp_table[index].flags, MSDP_FLAG_LIST)) { return; } flag = msdp_table[index].flags; sprintf(buf, "%c%c%c%c%s", IAC, SB, TELOPT_MSDP, MSDP_VAR, msdp_table[index].name); for (index = 0 ; index < mud->msdp_table_size ; index++) { if (flag != MSDP_FLAG_LIST) { if (HAS_BIT(d->msdp_data[index]->flags, flag) && !HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_LIST)) { cat_sprintf(buf, "%c%s", MSDP_VAL, msdp_table[index].name); } } else { if (HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_LIST)) { cat_sprintf(buf, "%c%s", MSDP_VAL, msdp_table[index].name); } } } cat_sprintf(buf, "%c%c", IAC, SE); descriptor_printf(d, "%s", buf); } void msdp_command_report(DESCRIPTOR_DATA *d, int index) { if (!HAS_BIT(msdp_table[index].flags, MSDP_FLAG_REPORTABLE)) { return; } SET_BIT(d->msdp_data[index]->flags, MSDP_FLAG_REPORTED); if (!HAS_BIT(msdp_table[index].flags, MSDP_FLAG_SENDABLE)) { return; } SET_BIT(d->msdp_data[index]->flags, MSDP_FLAG_UPDATED); } void msdp_command_reset(DESCRIPTOR_DATA *d, int index) { int flag; if (!HAS_BIT(msdp_table[index].flags, MSDP_FLAG_LIST)) { return; } flag = msdp_table[index].flags &= ~MSDP_FLAG_LIST; for (index = 0 ; index < mud->msdp_table_size ; index++) { if (HAS_BIT(d->msdp_data[index]->flags, flag)) { d->msdp_data[index]->flags = msdp_table[index].flags; } } } void msdp_command_send(DESCRIPTOR_DATA *d, int index) { if (HAS_BIT(d->msdp_data[index]->flags, MSDP_FLAG_SENDABLE)) { SET_BIT(d->msdp_data[index]->flags, MSDP_FLAG_UPDATED); SET_BIT(d->comm_flags, COMM_FLAG_MSDPUPDATE); } } void msdp_command_unreport(DESCRIPTOR_DATA *d, int index) { if (!HAS_BIT(msdp_table[index].flags, MSDP_FLAG_REPORTABLE)) { return; } DEL_BIT(d->msdp_data[index]->flags, MSDP_FLAG_REPORTED); } // Comment out if you don't want Arachnos Intermud support void msdp_configure_arachnos(DESCRIPTOR_DATA *d, int index) { char var[MAX_INPUT_LENGTH], val[MAX_INPUT_LENGTH]; char mud_name[MAX_INPUT_LENGTH], mud_host[MAX_INPUT_LENGTH], mud_port[MAX_INPUT_LENGTH]; char msg_user[MAX_INPUT_LENGTH], msg_time[MAX_INPUT_LENGTH], msg_body[MAX_INPUT_LENGTH]; char mud_players[MAX_INPUT_LENGTH], mud_uptime[MAX_INPUT_LENGTH], mud_update[MAX_INPUT_LENGTH]; char *pti, *pto; struct tm timeval_tm; time_t timeval_t; var[0] = val[0] = mud_name[0] = mud_host[0] = mud_port[0] = msg_user[0] = msg_time[0] = msg_body[0] = mud_players[0] = mud_uptime[0] = mud_update[0] = 0; pti = d->msdp_data[index]->value; while (*pti) { switch (*pti) { case MSDP_VAR: pti++; pto = var; while (*pti > MSDP_ARRAY_CLOSE) { *pto++ = *pti++; } *pto = 0; break; case MSDP_VAL: pti++; pto = val; while (*pti > MSDP_ARRAY_CLOSE) { *pto++ = *pti++; } *pto = 0; if (!strcmp(var, "MUD_NAME")) { strcpy(mud_name, val); } else if (!strcmp(var, "MUD_HOST")) { strcpy(mud_host, val); } else if (!strcmp(var, "MUD_PORT")) { strcpy(mud_port, val); } else if (!strcmp(var, "MSG_USER")) { strcpy(msg_user, val); } else if (!strcmp(var, "MSG_TIME")) { timeval_t = (time_t) atoll(val); timeval_tm = *localtime(&timeval_t); strftime(msg_time, 20, "%T %D", &timeval_tm); } else if (!strcmp(var, "MSG_BODY")) { strcpy(msg_body, val); } else if (!strcmp(var, "MUD_UPTIME")) { timeval_t = (time_t) atoll(val); timeval_tm = *localtime(&timeval_t); strftime(mud_uptime, 20, "%T %D", &timeval_tm); } else if (!strcmp(var, "MUD_UPDATE")) { timeval_t = (time_t) atoll(val); timeval_tm = *localtime(&timeval_t); strftime(mud_update, 20, "%T %D", &timeval_tm); } else if (!strcmp(var, "MUD_PLAYERS")) { strcpy(mud_players, val); } break; default: pti++; break; } } if (*mud_name && *mud_host && *mud_port) { if (!strcmp(msdp_table[index].name, "ARACHNOS_DEVEL")) { if (*msg_user && *msg_time && *msg_body) { arachnos_devel("%s %s@%s:%s devtalks: %s", msg_time, msg_user, mud_host, mud_port, msg_body); } } else if (!strcmp(msdp_table[index].name, "ARACHNOS_MUDLIST")) { if (*mud_uptime && *mud_update && *mud_players) { arachnos_mudlist("%18.18s %14.14s %5.5s %17.17s %17.17s %4.4s", mud_name, mud_host, mud_port, mud_update, mud_uptime, mud_players); } } } } struct msdp_type msdp_table[] = { { "ALIGNMENT", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "ARACHNOS_DEVEL", MSDP_FLAG_CONFIGURABLE|MSDP_FLAG_REPORTABLE, msdp_configure_arachnos }, { "ARACHNOS_MUDLIST", MSDP_FLAG_CONFIGURABLE, msdp_configure_arachnos }, { "COMMANDS", MSDP_FLAG_COMMAND|MSDP_FLAG_LIST, NULL }, { "CONFIGURABLE_VARIABLES", MSDP_FLAG_CONFIGURABLE|MSDP_FLAG_LIST, NULL }, { "HEALTH", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "EXPERIENCE", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "EXPERIENCE_MAX", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "HEALTH_MAX", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "LEVEL", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "LIST", MSDP_FLAG_COMMAND, msdp_command_list }, { "LISTS", MSDP_FLAG_LIST, NULL }, { "MANA", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "MANA_MAX", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "MONEY", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "MOVEMENT", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "MOVEMENT_MAX", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "REPORT", MSDP_FLAG_COMMAND, msdp_command_report }, { "REPORTABLE_VARIABLES", MSDP_FLAG_REPORTABLE|MSDP_FLAG_LIST, NULL }, { "REPORTED_VARIABLES", MSDP_FLAG_REPORTED|MSDP_FLAG_LIST, NULL }, { "RESET", MSDP_FLAG_COMMAND, msdp_command_reset }, { "ROOM", MSDP_FLAG_REPORTABLE, NULL }, { "ROOM_EXITS", MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE, NULL }, { "SEND", MSDP_FLAG_COMMAND, msdp_command_send }, { "SENDABLE_VARIABLES", MSDP_FLAG_SENDABLE|MSDP_FLAG_LIST, NULL }, { "SPECIFICATION", MSDP_FLAG_SENDABLE, NULL }, { "UNREPORT", MSDP_FLAG_COMMAND, msdp_command_unreport }, { "", 0, NULL } // End of table marker };