00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: telnetparty.c,v 1.27 2007-11-06 00:05:40 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025
00026 #include "telnetparty.h"
00027
00028 telnet_config_t telnet_config = {0};
00029
00030 static config_var_t telnet_config_vars[] = {
00031 {"vhost", &telnet_config.vhost, CONFIG_STRING},
00032 {"port", &telnet_config.port, CONFIG_INT},
00033 {"stealth", &telnet_config.stealth, CONFIG_INT},
00034 {"max_retries", &telnet_config.max_retries, CONFIG_INT},
00035 {0}
00036 };
00037
00038 EXPORT_SCOPE int telnetparty_LTX_start(egg_module_t *modinfo);
00039 static int telnetparty_close(int why);
00040
00041
00042 extern partyline_event_t telnet_party_handler;
00043
00044 static int telnet_idx = -1;
00045 static int telnet_port = 0;
00046
00047 static int telnet_on_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port);
00048 static int telnet_on_read(void *client_data, int idx, char *data, int len);
00049 static int telnet_on_eof(void *client_data, int idx, int err, const char *errmsg);
00050 static int telnet_on_delete(event_owner_t *owner, void *client_data);
00051 static int telnet_filter_read(void *client_data, int idx, char *data, int len);
00052 static int telnet_filter_write(void *client_data, int idx, const char *data, int len);
00053 static int telnet_filter_delete(void *client_data, int idx);
00054
00055 static int ident_result(void *client_data, const char *ip, int port, const char *reply);
00056 static int dns_result(void *client_data, const char *ip, char **hosts);
00057 static int process_results(telnet_session_t *session);
00058 static int telnet_pm_delete(event_owner_t *owner, void *client_data);
00059
00060 static event_owner_t telnet_generic_owner = {
00061 "telnetparty", 0,
00062 0, 0,
00063 0
00064 };
00065
00066 static event_owner_t telnet_sockbuf_owner = {
00067 "telnetparty", 0,
00068 0, 0,
00069 telnet_on_delete
00070 };
00071
00072 static event_owner_t telnet_partymember_owner = {
00073 "telnetparty", 0,
00074 0, 0,
00075 telnet_pm_delete
00076 };
00077
00078 static sockbuf_handler_t server_handler = {
00079 "telnet server",
00080 NULL, NULL, telnet_on_newclient,
00081 NULL, NULL
00082 };
00083
00084 #define TELNET_FILTER_LEVEL SOCKBUF_LEVEL_TEXT_ALTERATION
00085
00086 static sockbuf_filter_t telnet_filter = {
00087 "telnet filter", TELNET_FILTER_LEVEL,
00088 NULL, NULL, NULL,
00089 telnet_filter_read, telnet_filter_write, NULL,
00090 NULL, telnet_filter_delete
00091 };
00092
00093 static sockbuf_handler_t client_handler = {
00094 "telnet",
00095 NULL, telnet_on_eof, NULL,
00096 telnet_on_read, NULL
00097 };
00098
00099 int telnet_init()
00100 {
00101
00102 telnet_idx = egg_server(telnet_config.vhost, telnet_config.port, &telnet_port);
00103 sockbuf_set_handler(telnet_idx, &server_handler, NULL, NULL);
00104
00105 return(0);
00106 }
00107
00108 static int telnet_pm_delete(event_owner_t *owner, void *client_data)
00109 {
00110 telnet_session_t *session = client_data;
00111
00112 sockbuf_delete(session->idx);
00113
00114 return 0;
00115 }
00116
00117 void telnet_code(int idx, int cmd, int what)
00118 {
00119 char temp[3];
00120 temp[0] = TELNET_CMD;
00121 temp[1] = cmd;
00122 temp[2] = what;
00123 sockbuf_on_write(idx, TELNET_FILTER_LEVEL, temp, 3);
00124 }
00125
00126 void convert_ansi_code_to_mirc(int *tokens, int ntokens, char **dest, int *cur, int *max)
00127 {
00128 int ansi_to_mirc_colors[] = {1, 4, 3, 8, 2, 5, 10, 0};
00129 int i, in_bold, in_uline, in_reverse, fg, bg;
00130 char *newline;
00131 char buf[64];
00132
00133
00134 in_bold = in_uline = in_reverse = 0;
00135 fg = bg = -1;
00136 for (i = 0; i < ntokens; i++) {
00137 if (tokens[i] == 0) in_bold = in_uline = in_reverse = 0;
00138 else if (tokens[i] == 1) in_bold = 1;
00139 else if (tokens[i] == 4) in_uline = 1;
00140 else if (tokens[i] == 7) in_reverse = 1;
00141 else if (tokens[i] == 8) fg = bg = 99;
00142 else if (tokens[i] >= 30 && tokens[i] <= 37) {
00143 fg = ansi_to_mirc_colors[tokens[i] - 30];
00144 }
00145 else if (tokens[i] >= 40 && tokens[i] <= 47) {
00146 bg = ansi_to_mirc_colors[tokens[i] - 40];
00147 }
00148 }
00149 if (*max - *cur < 10) {
00150 *dest = realloc(*dest, *max + 10);
00151 *max += 10;
00152 }
00153 newline = buf;
00154 if (in_bold) *newline++ = '\002';
00155 if (in_uline) *newline++ = '\037';
00156 if (in_reverse) *newline++ = '\026';
00157 if (fg != -1 || bg != -1) {
00158 *newline++ = '\003';
00159 if (fg == -1) fg = 99;
00160 sprintf(newline, "%02d", fg);
00161 newline += 2;
00162 if (bg != -1) {
00163 sprintf(newline, ",%02d", bg);
00164 newline += 3;
00165 }
00166 }
00167 *newline = 0;
00168 egg_append_str(dest, cur, max, buf);
00169 }
00170
00171
00172
00173 int get_2(const char *data, int len, int *val)
00174 {
00175 if (isdigit(*data)) {
00176 *val = *data++ - '0';
00177 if (len > 1 && isdigit(*data)) {
00178 *val *= 10;
00179 *val += *data - '0';
00180 return(2);
00181 }
00182 return(1);
00183 }
00184 return(0);
00185 }
00186
00187 int convert_mirc_color_to_ansi(const char *data, int len, char **newline, int *cur, int *max)
00188 {
00189 const char *orig;
00190 char add[64], temp[64];
00191
00192 int mirc_to_ansi[] = {7, 0, 4, 2, 1, 1, 5, 1, 3, 2, 6, 6, 4, 5, 0, 0};
00193 int c1, c2, n;
00194
00195 orig = data;
00196 c1 = c2 = -1;
00197 n = get_2(data, len, &c1);
00198 if (n) {
00199 data += n; len -= n;
00200 if (len && *data == ',') {
00201 len--;
00202 data++;
00203 n = get_2(data, len, &c2);
00204 data += n;
00205 len -= n;
00206 }
00207 }
00208 strcpy(add, "\033[");
00209 if (c1 != -1) {
00210 if (c1 != 99) {
00211 c1 %= 16;
00212 sprintf(temp, "%d", 30+mirc_to_ansi[c1]);
00213 strcat(add, temp);
00214 }
00215 if (c2 != -1 && c2 != 99) {
00216 c2 %= 16;
00217 sprintf(temp, "%d", 40+mirc_to_ansi[c2]);
00218 if (c1 != 99) strcat(add, ";");
00219 strcat(add, temp);
00220 }
00221 strcat(add, "m");
00222 }
00223 else strcat(add, "0m");
00224 egg_append_str(newline, cur, max, add);
00225 return data - orig;
00226 }
00227
00228 void handle_ansi_code(const char **src, char **dest, int *cur, int *max)
00229 {
00230 const char *line = *src;
00231 int token, ntokens, *tokens;
00232
00233 if (*line++ != 27) return;
00234 *src = line;
00235 if (*line++ != '[') return;
00236
00237
00238 token = 0;
00239 ntokens = 0;
00240 tokens = NULL;
00241 while (*line) {
00242 if (*line >= '0' && *line <= '9') {
00243
00244 token *= 10;
00245 token += (*line - '0');
00246 }
00247 else if (*line == ';' || isalpha(*line)) {
00248
00249 tokens = realloc(tokens, sizeof(int) * (ntokens+1));
00250 tokens[ntokens++] = token;
00251 token = 0;
00252 if (isalpha(*line)) break;
00253 }
00254 else break;
00255 line++;
00256 }
00257
00258 if (*line == 'm') {
00259
00260 convert_ansi_code_to_mirc(tokens, ntokens, dest, cur, max);
00261 *src = line+1;
00262 }
00263
00264 if (tokens) free(tokens);
00265 }
00266
00267
00268 char *telnet_fix_line(const char *line)
00269 {
00270 char *newline;
00271 int cur, max;
00272
00273 cur = 0;
00274 max = 128;
00275 newline = malloc(max+1);
00276
00277 while (*line) {
00278 switch (*line) {
00279 case 7:
00280
00281 line++;
00282 break;
00283 case 8:
00284
00285 if (cur > 0) cur--;
00286 line++;
00287 break;
00288 case 27:
00289
00290 handle_ansi_code(&line, &newline, &cur, &max);
00291 break;
00292 default:
00293 if (cur >= max) {
00294 newline = realloc(newline, max+128);
00295 max += 128;
00296 }
00297 newline[cur++] = *line++;
00298 }
00299 }
00300 newline[cur] = 0;
00301
00302 return(newline);
00303 }
00304
00305 static void kill_session(telnet_session_t *session)
00306 {
00307 if (session->ident_id != -1) egg_ident_cancel(session->ident_id, 0);
00308 if (session->dns_id != -1) egg_dns_cancel(session->dns_id, 0);
00309 if (session->ip) free(session->ip);
00310 if (session->host) free(session->host);
00311 if (session->ident) free(session->ident);
00312 if (session->nick) free(session->nick);
00313 free(session);
00314 }
00315
00316 static int telnet_on_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port)
00317 {
00318 telnet_session_t *session;
00319
00320 session = calloc(1, sizeof(*session));
00321 session->ip = strdup(peer_ip);
00322 session->port = peer_port;
00323 session->idx = newidx;
00324
00325 sockbuf_set_handler(newidx, &client_handler, session, &telnet_sockbuf_owner);
00326 sockbuf_attach_filter(newidx, &telnet_filter, session);
00327 socktimer_on(newidx, 60, 0, NULL, NULL, &telnet_generic_owner);
00328 linemode_on(newidx);
00329
00330
00331
00332 if (telnet_config.stealth) {
00333 session->state = STATE_RESOLVE;
00334 session->flags |= STEALTH_LOGIN;
00335 }
00336 else {
00337 egg_iprintf(newidx, "Hello %s/%d!\r\n", peer_ip, peer_port);
00338 sockbuf_write(newidx, "\r\nPlease enter your nickname.\r\n", -1);
00339 session->state = STATE_NICKNAME;
00340 session->count = 0;
00341 }
00342
00343
00344 session->ident_id = egg_ident_lookup(peer_ip, peer_port, telnet_port, -1, ident_result, session, &telnet_generic_owner);
00345 session->dns_id = egg_dns_reverse(peer_ip, -1, dns_result, session, &telnet_generic_owner);
00346
00347 return(0);
00348 }
00349
00350 static int ident_result(void *client_data, const char *ip, int port, const char *reply)
00351 {
00352 telnet_session_t *session = client_data;
00353
00354 session->ident_id = -1;
00355 if (reply) session->ident = strdup(reply);
00356 else session->ident = strdup("~telnet");
00357 process_results(session);
00358 return(0);
00359 }
00360
00361 static int dns_result(void *client_data, const char *ip, char **hosts)
00362 {
00363 telnet_session_t *session = client_data;
00364 const char *host;
00365
00366 session->dns_id = -1;
00367 if (!hosts || !hosts[0]) host = ip;
00368 else host = hosts[0];
00369
00370 session->host = strdup(host);
00371 process_results(session);
00372 return(0);
00373 }
00374
00375 static int process_results(telnet_session_t *session)
00376 {
00377 char fakehost[512];
00378
00379 if (!session->ident || !session->host) return(0);
00380
00381 if (session->state == STATE_PARTYLINE) {
00382 partyline_update_info(session->party, session->ident, session->host);
00383 return(0);
00384 }
00385 if (session->flags & STEALTH_LOGIN) {
00386 snprintf(fakehost, sizeof(fakehost), "-telnet!%s@%s", session->ident, session->host);
00387 fakehost[sizeof(fakehost)-1] = 0;
00388 if (!user_lookup_by_irchost(fakehost)) {
00389 sockbuf_delete(session->idx);
00390 return(0);
00391 }
00392 sockbuf_write(session->idx, "\r\nPlease enter your nickname.\r\n", -1);
00393 session->state = STATE_NICKNAME;
00394 }
00395 return(0);
00396 }
00397
00398 static int telnet_on_read(void *client_data, int idx, char *data, int len)
00399 {
00400 telnet_session_t *session = client_data;
00401 char *newline;
00402
00403 switch (session->state) {
00404 case STATE_PARTYLINE:
00405 newline = telnet_fix_line(data);
00406 if (newline) {
00407 partyline_on_input(NULL, session->party, newline, strlen(newline));
00408 free(newline);
00409 }
00410 break;
00411 case STATE_NICKNAME:
00412 session->nick = strdup(data);
00413 session->state = STATE_PASSWORD;
00414 session->flags |= TFLAG_PASSWORD;
00415 telnet_code(session->idx, TELNET_WILL, TELNET_ECHO);
00416 sockbuf_write(session->idx, "Please enter your password.\r\n", -1);
00417 break;
00418 case STATE_PASSWORD:
00419 session->flags &= ~TFLAG_PASSWORD;
00420 telnet_code(session->idx, TELNET_WONT, TELNET_ECHO);
00421 session->user = user_lookup_authed(session->nick, data);
00422 if (!session->user) {
00423 sockbuf_write(session->idx, "Invalid username/password.\r\n\r\n", -1);
00424 session->count++;
00425 if (session->count > telnet_config.max_retries) {
00426 sockbuf_delete(session->idx);
00427 break;
00428 }
00429 free(session->nick);
00430 session->nick = NULL;
00431 sockbuf_write(session->idx, "Please enter your nickname.\r\n", -1);
00432 session->state = STATE_NICKNAME;
00433 }
00434 else {
00435 socktimer_off(idx);
00436 session->party = partymember_new(-1, session->user, NULL, session->nick, session->ident ? session->ident : "~telnet", session->host ? session->host : session->ip, &telnet_party_handler, session, &telnet_partymember_owner);
00437 session->state = STATE_PARTYLINE;
00438 egg_iprintf(idx, "\r\nWelcome to the telnet partyline interface!\r\n");
00439 if (session->ident) egg_iprintf(idx, "Your ident is: %s\r\n", session->ident);
00440 if (session->host) egg_iprintf(idx, "Your hostname is: %s\r\n", session->host);
00441
00442 partychan_join_name("*", session->party, 0);
00443 }
00444 break;
00445 }
00446 return(0);
00447 }
00448
00449 static int telnet_on_eof(void *client_data, int idx, int err, const char *errmsg)
00450 {
00451 telnet_session_t *session = client_data;
00452
00453 if (session->party) {
00454 if (!err) errmsg = "Client disconnected";
00455 else if (!errmsg) errmsg = "Unknown error";
00456 partymember_delete(session->party, NULL, errmsg);
00457
00458
00459
00460 } else {
00461 sockbuf_delete(idx);
00462 }
00463 return(0);
00464 }
00465
00466 static int telnet_on_delete(event_owner_t *owner, void *client_data)
00467 {
00468 telnet_session_t *session = client_data;
00469
00470 if (session->party) {
00471 partymember_delete(session->party, NULL, "Deleted!");
00472 session->party = NULL;
00473 }
00474 kill_session(session);
00475 return(0);
00476 }
00477
00478 static int telnet_filter_read(void *client_data, int idx, char *data, int len)
00479 {
00480 unsigned char *cmd;
00481 int type, arg, remove;
00482 telnet_session_t *session = client_data;
00483
00484 cmd = (unsigned char *) data;
00485 while ((cmd = memchr(cmd, TELNET_CMD, len))) {
00486 type = *(cmd+1);
00487 switch (type) {
00488 case TELNET_AYT:
00489 sockbuf_write(idx, "[YES]\r\n", 7);
00490 remove = 1;
00491 break;
00492 case TELNET_CMD:
00493 cmd++;
00494 remove = 1;
00495 break;
00496 case TELNET_DO:
00497 arg = *(cmd+2);
00498 if (arg == TELNET_ECHO) {
00499 if (!(session->flags & TFLAG_ECHO)) {
00500 telnet_code(idx, TELNET_WILL, arg);
00501 session->flags |= TFLAG_ECHO;
00502 }
00503 }
00504 else telnet_code(idx, TELNET_WONT, arg);
00505 remove = 3;
00506 break;
00507 case TELNET_DONT:
00508 arg = *(cmd+2);
00509 if (arg == TELNET_ECHO) {
00510 if (session->flags & TFLAG_ECHO) {
00511 telnet_code(idx, TELNET_WONT, arg);
00512 session->flags &= ~TFLAG_ECHO;
00513 }
00514 }
00515 remove = 3;
00516 break;
00517 case TELNET_WILL:
00518 remove = 3;
00519 break;
00520 case TELNET_WONT:
00521 remove = 3;
00522 break;
00523 default:
00524 remove = 2;
00525 }
00526 memmove(cmd, cmd+remove, len - (cmd - (unsigned char *)data) - remove + 1);
00527 len -= remove;
00528 }
00529
00530 if (len) {
00531 if (session->flags & TFLAG_ECHO && !(session->flags & TFLAG_PASSWORD)) sockbuf_on_write(idx, TELNET_FILTER_LEVEL, data, len);
00532 sockbuf_on_read(idx, TELNET_FILTER_LEVEL, data, len);
00533 }
00534 return(0);
00535 }
00536
00537
00538 static int telnet_filter_write(void *client_data, int idx, const char *data, int len)
00539 {
00540 char *newline;
00541 const char *filterchars = "\n\r\003\002\007\017\026\037\255";
00542 char temp[64];
00543 int i, cur, max, n, code, esc;
00544
00545 cur = 0;
00546 max = 128;
00547 newline = malloc(max+1);
00548
00549 code = 0;
00550 esc = -1;
00551 while (len > 0) {
00552 switch (*data) {
00553 case '\002':
00554 esc = 1;
00555 break;
00556 case '\003':
00557 code = 1;
00558 data++; len--;
00559 n = convert_mirc_color_to_ansi(data, len, &newline, &cur, &max);
00560 data += n;
00561 len -= n;
00562 break;
00563 case '\007':
00564
00565 data++; len--;
00566 break;
00567 case '\017':
00568 esc = 0;
00569 break;
00570 case '\026':
00571 esc = 7;
00572 break;
00573 case '\037':
00574 esc = 4;
00575 break;
00576 case '\r':
00577 case '\n':
00578 if (code) {
00579
00580
00581
00582 egg_append_str(&newline, &cur, &max, "\033[0m");
00583 code = 0;
00584 }
00585 if (*data != '\r') {
00586
00587
00588 egg_append_str(&newline, &cur, &max, "\r\n");
00589 }
00590 data++;
00591 len--;
00592 break;
00593 case '\255':
00594
00595
00596 egg_append_str(&newline, &cur, &max, "\255\255");
00597 data++;
00598 len--;
00599 break;
00600 default:
00601 for (i = 0; i < sizeof(temp)-1 && i < len; i++) {
00602 if (strchr(filterchars, *data)) break;
00603 temp[i] = *data++;
00604 }
00605 temp[i] = 0;
00606 egg_append_str(&newline, &cur, &max, temp);
00607 len -= i;
00608 }
00609
00610 if (esc != -1) {
00611
00612 sprintf(temp, "\033[%dm", esc);
00613 egg_append_str(&newline, &cur, &max, temp);
00614 data++; len--;
00615 esc = -1;
00616
00617
00618
00619 code = 1;
00620 }
00621 }
00622 newline[cur] = 0;
00623 if (cur > 0) {
00624 n = sockbuf_on_write(idx, TELNET_FILTER_LEVEL, newline, cur);
00625 }
00626 else n = 0;
00627 free(newline);
00628 return(n);
00629 }
00630
00631 static int telnet_filter_delete(void *client_data, int idx)
00632 {
00633
00634
00635 return(0);
00636 }
00637
00638 static int telnetparty_close(int why)
00639 {
00640 void *config_root;
00641
00642 config_root = config_get_root("eggdrop");
00643 config_unlink_table(telnet_config_vars, config_root, "telnetparty", 0, NULL);
00644
00645 sockbuf_delete(telnet_idx);
00646 return(0);
00647 }
00648
00649 int telnetparty_LTX_start(egg_module_t *modinfo)
00650 {
00651 void *config_root;
00652
00653 telnet_generic_owner.module = telnet_sockbuf_owner.module = telnet_partymember_owner.module = modinfo;
00654 modinfo->name = "telnetparty";
00655 modinfo->author = "eggdev";
00656 modinfo->version = "1.0.0";
00657 modinfo->description = "telnet support for the partyline";
00658 modinfo->close_func = telnetparty_close;
00659
00660
00661 memset(&telnet_config, 0, sizeof(telnet_config));
00662 telnet_config.max_retries = 3;
00663
00664
00665 config_root = config_get_root("eggdrop");
00666 config_link_table(telnet_config_vars, config_root, "telnetparty", 0, NULL);
00667 config_update_table(telnet_config_vars, config_root, "telnetparty", 0, NULL);
00668
00669 telnet_init();
00670 return(0);
00671 }