/** * MUD based dictionary, conforms to the DICT new protocol found in RFC 2229. * See ftp://ftp.isi.edu/in-notes/rfc2229.txt for more information. * @author Taffyd@Discworld * @changes 5-2-2001 Pinkfish * Converted to work as a handler. */ #include <network.h> // #define DNS_LOOKUP #define DICT_SERVER_NAME "dict.org" #define DICT_SERVER_IP "66.111.36.30" #define DISCONNECTED 0 #define WAITING_FOR_CONNECT 1 #define READY 2 #define RECEIVING 3 #define SENDING_DEFINE 4 #define SENDING_MATCH 5 #define WAITING_FOR_DNS 6 #define INACTIVE 0 #define DEFINE 1 #define MATCH 2 #define SEARCH_MODE_ALL "*" #define DEFAULT_SEARCH_MODE "web1913" #define DEBUGGER "pinkfish" //#define DEBUGGER "" /** * This class handles connection details for each person using * the dictionary. * @member fd the file descriptor of the socket currently being * used by the dictionary. * member dns_key the resolve() key used when doing a nslookup. */ // string *dictionaries; // string *capabilities; class request { string word; string search_mode; int type; int i; function callback; } class connection_data { int fd; int dns_key; string message; mixed definitions; mixed *working; string ip_address; int status; int count; string search_mode; class request current_request; } inherit CLIENT; private class connection_data _connection; private class request* _requests; void remove_request(class request bing); void close_connection(); void inform_of_problem(class request bing, string str); void send_request(class request bing); void make_connection(); void check_send(); void create() { client::create(); SetSocketType(STREAM); _requests = ({ }); } /* create() */ void close_socket( int fd, object who ) { if ( _connection->fd ) { eventWrite(fd, "QUIT\r\n" ); eventAbortCallback( fd ); close_connection(); } } /* close_socket() */ void do_callback(function callb, string word, mixed result, mixed* data) { call_out((: evaluate($1, $2, $3, $4) :), 0, callb, word, result, data); } /* do_callback() */ void eventRead(int fd, string message) { class connection_data dict; string *bits; string *lines; string line; string word; string extra; string dictionary_name; mixed *bing; mixed *fluff; int i; int j; int ignore; //tell_creator(DEBUGGER, "Got %O\n", message); /* Check to see if the message is valid. */ if ( !stringp( message ) ) { return; } /* Find the user for this connection */ dict = _connection; lines = explode( message, "\r\n" ); foreach ( line in lines ) { if ( !sizeof( line ) ) { line = "\n"; } if ( line == "." ) { dict->definitions += ({ dict->working }); dict->count = -1; continue; } bits = explode( line, " " ); if ( !sizeof( bits ) ) { continue; } //tell_creator(DEBUGGER, sprintf("Event %s received in status %d\n[%s]\n", //bits[0], dict->status, line)); switch ( bits[ 0 ] ) { case "150": dict->count++; dict->working = ({ }); dict->status = RECEIVING; word = 0; extra = 0; dictionary_name = 0; break; case "151": if ( dict->status == RECEIVING && ( sscanf( line, "151 \"%s\" %s \"%s\"", word, extra, dictionary_name ) == 3 ) ) { dict->working += ({ ({ word, dictionary_name, extra }) }); } else { //tell_creator( DEBUGGER, "Invalid 151 error code, %s, %s, %s.\n", //word, extra, dictionary_name ); } break; case "152": dict->count++; dict->working = ({ }); dict->status = RECEIVING; word = 0; extra = 0; dictionary_name = 0; break; case "220": if (dict->status == WAITING_FOR_CONNECT) { dict->status = READY; check_send(); } /* tell_object( who, "The dictionary's pages shuffle about. It is now " "ready for a query.\n" ); */ // dict->capabilities = explode( bits[ <2 ][1..<2], "." ); break; case "250": //tell_creator(DEBUGGER, "Start...\n"); switch(dict->current_request->type) { case DEFINE: bing = ({ }); for ( i = 0; i < sizeof( dict->definitions ); i++ ) { foreach( fluff in dict->definitions[ i ] ) { fluff[2] = replace( fluff[2], ({ " ", " ", "\t", " " }) ); ignore = 0; for (j = 0; j < sizeof(bing); j++) { if (bing[j][2] == fluff[2]) { ignore = 1; } } if (!ignore) { bing += ({ fluff }); } } } //tell_creator(DEBUGGER, "%O %O\n", bing, dict->definitions); if (dict->current_request->callback) { do_callback(dict->current_request->callback, dict->current_request->word, NETWORK_SUCCESS, bing); } dict->status = READY; remove_request(dict->current_request); break; case MATCH: if (dict->current_request->callback) { bing = ({ }); for(i=0; i<sizeof(dict->definitions); i++) { foreach(line in dict->definitions[i]) { if(sscanf(line, "%s \"%s\"", extra, word) == 2) { bing += ({ ({ extra, word }) }); } } } //tell_creator(DEBUGGER, "+++ %O\n", dict); do_callback(dict->current_request->callback, dict->current_request->word, NETWORK_SUCCESS, bing); } dict->status = READY; remove_request(dict->current_request); } //tell_creator(DEBUGGER, "--- Fallout!\n"); return; break; case "530": inform_of_problem(dict->current_request, "Error from server."); dict->status = READY; remove_request(dict->current_request); //close_socket( fd, who ); return; break; case "552": if (dict->current_request->callback) { do_callback(dict->current_request->callback, dict->current_request->word, NETWORK_SUCCESS, ({ })); } dict->status = READY; remove_request(dict->current_request); return; break; default: if ( dict->status == RECEIVING ) { switch(dict->current_request->type) { case DEFINE: dict->working[<1][<1] += line; break; case MATCH: dict->working += ({ line }); } } else //tell_creator(DEBUGGER, "Line not added, status " + //dict->status + "\n"); break; } } } /* eventRead() */ void got_ip_address( string address, string ip_address, int key ) { tell_creator( "taffyd", "%s, %s\n", address, ip_address ); //tell_creator(DEBUGGER, "Ig? %O %O %O %O\n", key, _connection, ip_address, address); /* if ( _connection->dns_key != key ) { return ; } */ if ( !address || !ip_address ) { ip_address = "127.0.0.1"; //inform_of_problem(0, "Unable to lookup dns address."); //return; } //tell_creator(DEBUGGER, "Setup ip.\n"); _connection->ip_address = ip_address; make_connection(); } /* got_ip_address() */ void make_connection() { int key; int new_fd; //tell_creator(DEBUGGER, "Making connection.\n"); if (!_connection || !_connection->fd) { if (!_connection || !_connection->ip_address) { _connection = new(class connection_data, fd : 0, status : WAITING_FOR_DNS, count : -1, definitions : ({ }), dns_key : key ); #ifdef DNS_LOOKUP _connection->dns_key = resolve( DICT_SERVER_NAME, "got_ip_address" ); #else got_ip_address( DICT_SERVER_NAME, DICT_SERVER_IP, 0 ); #endif } else { new_fd = eventCreateSocket( _connection->ip_address, 2628 ); if ( new_fd < 0 ) { inform_of_problem(0, "unable to connect"); return; } _connection->fd = new_fd; _connection->status = WAITING_FOR_CONNECT; call_out( "close_socket", 120, new_fd, this_player() ); } } } /* make_connection() */ void close_connection() { int fd; if (_connection && _connection->fd) { fd = _connection->fd; _connection->fd = 0; close_socket( fd, this_player() ); inform_of_problem(0, "socket closed"); } } /* close_connection() */ void check_send() { //tell_creator(DEBUGGER, "%O\n", _connection); if (!_connection || _connection->fd == 0) { make_connection(); } else if (_connection->status == READY && sizeof(_requests)) { send_request(_requests[0]); } } /* check_send() */ void send_request(class request bing) { //tell_creator(DEBUGGER, "Sending request %O\n", bing); switch (bing->type) { case DEFINE : eventWrite(_connection->fd, sprintf("DEFINE %s %s\r\n", bing->search_mode, bing->word)); _connection->status = SENDING_DEFINE; break; case MATCH : eventWrite(_connection->fd, sprintf("MATCH %s . %s\r\n", bing->search_mode, bing->word)); _connection->status = SENDING_MATCH; break; } _connection->current_request = bing; _connection->definitions = ({ }); } /* send_request() */ void remove_request(class request bing) { int i; for (i = 0; i < sizeof(_requests); i++) { if (_requests[i] == bing) { _requests = _requests[0..i - 1] + _requests[i + 1..]; break; } } _connection->definitions = ({ }); check_send(); } /* remove_request() */ void add_request(class request bing) { //tell_creator(DEBUGGER, "Adding request %O\n", bing); _requests += ({ bing }); check_send(); } /* add_request() */ int define_word(string word, int all, function call_back) { class request request; request = new(class request); request->word = word; if (all) { request->search_mode = SEARCH_MODE_ALL; } else { request->search_mode = DEFAULT_SEARCH_MODE; } request->type = DEFINE; request->callback = call_back; /* eventWrite(dict->fd, sprintf("DEFINE %s %s\r\n", dict->search_mode, dict->word)); */ add_request(request); } /* define_word() */ int spell_word(string word, int all, function call_back) { class request request; request = new(class request); request->word = word; if (all) { request->search_mode = SEARCH_MODE_ALL; } else { request->search_mode = DEFAULT_SEARCH_MODE; } request->type = MATCH; request->callback = call_back; /* eventWrite(dict->fd, sprintf("MATCH %s . %s\r\n", dict->search_mode, dict->current_word)); */ add_request(request); } void inform_of_problem(class request bing, string mess) { if (bing) { do_callback(bing->callback, bing->word, mess, ({ })); remove_request(bing); } else { foreach (bing in _requests) { do_callback(bing->callback, bing->word, mess, ({ })); } _requests = ({ }); } } /* inform_of_problem() */ void dest_me() { close_connection(); client::dest_me(); } /* dest_me() */