// I3 server.
// This file written completely by Tim Johnson (Tim@TimMUD)
// Started by Tim on May 7, 2003.
// http://cie.imaginary.com/protocols/intermud3.html#errors
#include <net/socket.h>
#include <socket_err.h>
#define DEB_IN  1	// Debug-Incoming
#define DEB_OUT 2	// Debug-Outgoing
#define DEB_INVALID 3	// Debug-Invalid
#define DEB_OTHER 0	// Debug-Other
#define MYSERVER 9000	// Port to accept connections on.
#define DEBUGGER "tim"	// Name of who to display debugging info to.
#undef DEBUGGER
#define DEBUGGER "tim"
#define MAXIMUM_RETRIES 5
// SEND_WHOLE_MUDLIST makes it act like the official I3 server instead of like the I3 specs
#define SEND_WHOLE_MUDLIST
// SEND_WHOLE_CHANLIST makes it act like the official I3 server instead of like the I3 specs
#define SEND_WHOLE_CHANLIST
inherit "/std/save.c";

// Unsaved variables...
static private int router_socket;
	// socket that the router is using
static private mapping sockets;
	// physically connected sockets and their info
static private mapping connected_muds;
	// muds that have successfully done a startup
	// (key=mudname, value=fd)
//static private
mapping listening;
	// list of muds listening to each channel
	// (key=chan name, value=mud array)

// Saved variables...
string router_name; // Name of the router.
string *router_list; // Ordered list of routers to use.
mapping mudinfo; // Info about all the muds which the router knows about.
mapping channels; // Info about all the channels the router handles.
mapping channel_updates; // Tells when a channel was last changed.
int channel_update_counter; // Counter for the most recent change.
	// Why is this not a part of the channels mapping?
	// Because I need to remember that some channels got deleted.
mapping mudinfo_updates; // Like channel_updates except for muds.
int mudinfo_update_counter; // Similar to channel_update_counter

// Prototypes
void write_data(int fd, mixed data);
void close_connection(int fd);
static mapping muds_on_this_fd(int fd);
static mapping muds_not_on_this_fd(int fd);
static void broadcast_data(mapping targets, mixed data);
// Ones with their own files...
static void broadcast_chanlist(string channame);
static void broadcast_mudlist(string mudname);
static varargs void debug(string str, int level);
static void process_channel(int fd, mixed *info);
static void process_startup_req(int protocol, mixed info, int fd);
static void read_callback(int fd, mixed info);
static void remove_mud(string mudname);
static void send_chanlist_reply(string mudname, int old_chanid);
static void send_mudlist(string mudname);
static void send_mudlist_updates(string updating_mudname, int old_mudlist_id);
static void send_startup_reply(string mudname);
static void send_error(string mud, string user, string errcode, string errmsg, mixed *info);
// core_stuff.h...
static void create();
static void setup();
void remove();
// funcs.h...
static mapping muds_on_this_fd(int fd);
int value_equals(string a,int b, int c);
static mapping muds_not_on_this_fd(int fd);
int value_not_equals(string a,int b, int c);
// socket_stuff.h
static void close_callback(int fd);
static void listen_callback(int fd);
static void write_data_retry(int fd, mixed data, int counter);
static void close_connection(int fd);
static void write_data(int fd, mixed data);
static void broadcast_data(mapping targets, mixed data);

// Code for all the stuff in the prototypes...
#include "broadcast_chanlist.h"
#include "broadcast_mudlist.h"
#include "debug.h"
#include "process_channel.h"
#include "process_startup_req.h"
#include "read_callback.h"
#include "remove_mud.h"
#include "send_chanlist_reply.h"
#include "send_mudlist_updates.h"
#include "send_startup_reply.h"
#include "send_error.h"

#include "core_stuff.h"
#include "funcs.h"
#include "socket_stuff.h"



// Debugging stuff...
mapping query_mudinfo(){ return copy(mudinfo); }
void get_info() {
	write (
	"router_name: "+router_name+
	"\nrouter_list"+identify(router_list)+
	"\nchannel_update_counter: "+ channel_update_counter+
	"\nchannels:"+dump_variable(channels)+
	"\nchannel_updates:"+dump_variable(channel_updates)+
	"\nlistening:"+dump_variable(listening)+
	"\nmudinfo:"+dump_variable(mudinfo)+
	"\nmudinfo_update_counter: "+ mudinfo_update_counter+
	"\nmudinfo_updates:"+dump_variable(mudinfo_updates)+
	"\nconnected:"+dump_variable(connected_muds)+"\n");
}
void clear(){ string mudname; foreach(mudname in keys(mudinfo)) remove_mud(mudname); }