Changeset 5900:3dbe762edefe in roaraudio
- Timestamp:
- 04/14/13 16:01:18 (11 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
plugins/roard/protocol-irc.c
r5899 r5900 29 29 #define MAX_CHANNELS 8 30 30 31 static int on_nick(int client, const char * cmd, char * args, char * text);32 static int on_user(int client, const char * cmd, char * args, char * text);33 static int on_quit(int client, const char * cmd, char * args, char * text);34 static int on_ping(int client, const char * cmd, char * args, char * text);35 static int on_lusers(int client, const char * cmd, char * args, char * text);36 static int on_whois(int client, const char * cmd, char * args, char * text);37 static int on_privmsg(int client, const char * cmd, char * args, char * text);38 39 static int on_list(int client, const char * cmd, char * args, char * text);40 static int on_join(int client, const char * cmd, char * args, char * text);41 static int on_part(int client, const char * cmd, char * args, char * text);42 static int on_names(int client, const char * cmd, char * args, char * text);43 44 static int on_topic(int client, const char * cmd, char * args, char * text);45 46 static int do_join(int client, const char * channel);47 static int do_part(int client, const char * channel);48 static int do_names(int client, const char * channel);49 50 static void cb_client_delete(struct roar_notify_core * core, struct roar_event * event, void * userdata);51 52 31 struct channel { 53 32 char * name; … … 80 59 static const struct command { 81 60 const char * name; 82 int (*func)(int client, const char * cmd, char * args, char * text); 83 } g_commands[] = { 61 int (*func)(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text); 62 } g_commands[]; 63 64 static int is_valid_name (const char * name) { 65 register char c; 66 67 for (; (c = *name) != 0; name++) { 68 if ( !(isalnum(c) || c == '-' || c == '_') ) 69 return 0; 70 } 71 72 return 1; 73 } 74 75 static void strip_nl(char * str) { 76 register char c; 77 78 for (; (c = *str) != 0; str++) { 79 if ( c == '\r' || c == '\n' ) { 80 *str = 0; 81 return; 82 } 83 } 84 } 85 86 static char * get_nick(int client) { 87 struct roar_client * c; 88 clients_get(client, &c); 89 return c->name; 90 } 91 92 static const char * get_ident(int client) { 93 static char buf[80]; 94 struct roar_client * c; 95 clients_get(client, &c); 96 97 if ( c->uid == -1 ) { 98 buf[0] = '~'; 99 buf[1] = 0; 100 } else { 101 snprintf(buf, sizeof(buf)-1, "uid%i~", c->uid); 102 buf[sizeof(buf)-1] = 0; 103 } 104 105 return buf; 106 } 107 108 static const char * get_node(int client) { 109 struct roar_client * c; 110 static char buf_nnode[80]; 111 char * nnode; 112 113 clients_get(client, &c); 114 115 roar_nnode_to_str(&(c->nnode), buf_nnode, sizeof(buf_nnode)); 116 117 nnode = strstr(buf_nnode, ": "); 118 if ( nnode == NULL ) { 119 nnode = "unknown~"; 120 } else { 121 nnode += 2; 122 } 123 124 return nnode; 125 } 126 127 static const char * get_ufull(int client) { 128 struct roar_client * c; 129 static char buf[80]; 130 const char * ident = get_ident(client); 131 const char * nnode = get_node(client); 132 133 clients_get(client, &c); 134 135 snprintf(buf, sizeof(buf)-1, "%s!%s@%s", c->name, ident, nnode); 136 137 buf[sizeof(buf)-1] = 0; 138 139 return buf; 140 } 141 142 static const char * get_realname(int client) { 143 (void)client; 144 return "(no realname)"; 145 } 146 147 static int get_client_by_nick(const char * nick) { 148 struct roar_client * c; 149 int i; 150 151 for (i = 0; i < ROAR_CLIENTS_MAX; i++) { 152 if ( clients_get(i, &c) != 0 ) 153 continue; 154 155 if ( !!strcasecmp(c->name, nick) ) 156 continue; 157 158 return i; 159 } 160 161 return -1; 162 } 163 164 static struct channel * get_channel(const char * name) { 165 struct channel * c; 166 size_t i; 167 168 for (i = 0; i < MAX_CHANNELS; i++) { 169 c = &(g_state->g_channels[i]); 170 171 if ( !c->client_count ) 172 continue; 173 174 if ( !!strcasecmp(c->name, name) ) 175 continue; 176 177 return c; 178 } 179 180 return NULL; 181 } 182 183 static size_t get_listener_list(int client, const char * channel, int ** listener) { 184 struct channel * c; 185 static int clients[ROAR_CLIENTS_MAX]; 186 size_t ret = 0; 187 size_t i, k; 188 int j; 189 int found; 190 191 for (i = 0; i < MAX_CHANNELS; i++) { 192 c = &(g_state->g_channels[i]); 193 194 if ( !c->client_count ) 195 continue; 196 197 if ( c->clients[client] < 1 ) 198 continue; 199 200 if ( channel != NULL && !!strcasecmp(c->name, channel) ) 201 continue; 202 203 for (j = 0; j < ROAR_CLIENTS_MAX; j++) { 204 if ( c->clients[j] > 0 ) { 205 found = 0; 206 for (k = 0; k < ret; k++) { 207 if ( clients[k] == j ) { 208 found = 1; 209 } 210 } 211 if ( !found ) { 212 clients[ret] = j; 213 ret++; 214 } 215 } 216 } 217 } 218 219 *listener = clients; 220 221 return ret; 222 } 223 224 static void put_printf(int client, struct roar_buffer ** obuffer, const char *format, ...) { 225 va_list ap; 226 struct roar_buffer * buf; 227 size_t len = 2048; 228 void * data; 229 int ret; 230 231 if ( roar_buffer_new_data(&buf, len, &data) == -1 ) 232 return; 233 234 va_start(ap, format); 235 ret = vsnprintf(data, len-1, format, ap); 236 va_end(ap); 237 238 if ( roar_buffer_set_len(buf, strlen(data)) == -1 ) { 239 roar_buffer_free(buf); 240 return; 241 } 242 243 if ( obuffer == NULL ) { 244 // TODO: FIXME: find a better way to to this. 245 clients_add_output(client, &buf); 246 } else { 247 if ( roar_buffer_moveintoqueue(obuffer, &buf) == -1 ) 248 roar_buffer_free(buf); 249 } 250 } 251 252 static int do_join(int client, const char * channel) { 253 struct channel * c = NULL; 254 size_t i; 255 256 if ( channel[0] != '#' ) 257 return -1; 258 259 if ( !is_valid_name(channel+1) ) 260 return -1; 261 262 for (i = 0; i < MAX_CHANNELS; i++) { 263 if ( !g_state->g_channels[i].client_count ) 264 continue; 265 266 if ( !!strcasecmp(g_state->g_channels[i].name, channel) ) 267 continue; 268 269 c = &(g_state->g_channels[i]); 270 break; 271 } 272 273 if ( c == NULL ) { 274 for (i = 0; i < MAX_CHANNELS; i++) { 275 if ( g_state->g_channels[i].client_count ) 276 continue; 277 278 c = &(g_state->g_channels[i]); 279 break; 280 } 281 282 if ( c == NULL ) 283 return -1; 284 285 memset(c, 0, sizeof(*c)); 286 287 c->name = roar_mm_strdup(channel); 288 } 289 290 if ( c->clients[client] ) 291 return -1; 292 293 c->clients[client] = 1; 294 c->client_count++; 295 296 return 0; 297 } 298 299 static int do_part(int client, const char * channel) { 300 struct channel * c = NULL; 301 size_t i; 302 303 for (i = 0; i < MAX_CHANNELS; i++) { 304 if ( !g_state->g_channels[i].client_count ) 305 continue; 306 307 if ( !!strcasecmp(g_state->g_channels[i].name, channel) ) 308 continue; 309 310 if ( !g_state->g_channels[i].clients[client] ) 311 return -1; 312 313 c = &(g_state->g_channels[i]); 314 break; 315 } 316 317 c->clients[client] = 0; 318 c->client_count--; 319 320 if ( !c->client_count ) { 321 roar_mm_free(c->name); 322 323 if ( c->topic.text != NULL ) 324 roar_mm_free(c->topic.text); 325 if ( c->topic.user != NULL ) 326 roar_mm_free(c->topic.user); 327 } 328 329 return 0; 330 } 331 332 static int do_names(int client, struct roar_buffer ** obuffer, const char * channel) { 333 const char * nick = get_nick(client); 334 size_t i; 335 char buf[256]; 336 size_t len, offset; 337 char * c_nick; 338 int j; 339 340 for (i = 0; i < MAX_CHANNELS; i++) { 341 if ( !g_state->g_channels[i].client_count ) 342 continue; 343 344 if ( !!strcasecmp(g_state->g_channels[i].name, channel) ) 345 continue; 346 347 offset = 0; 348 349 for (j = 0; j < ROAR_CLIENTS_MAX; j++) { 350 if ( g_state->g_channels[i].clients[j] == 0 ) 351 continue; 352 353 c_nick = get_nick(j); 354 len = strlen(c_nick); 355 if ( (offset + len + 3) > sizeof(buf) ) { 356 buf[offset] = 0; 357 put_printf(client, obuffer, ":%s 353 %s = %s :%s\n", g_state->server_name, nick, channel, buf); 358 offset = 0; 359 } 360 361 memcpy(buf + offset, c_nick, len); 362 offset += len; 363 buf[offset] = ' '; 364 offset++; 365 buf[offset] = 0; 366 } 367 368 if ( offset ) { 369 buf[offset] = 0; 370 put_printf(client, obuffer, ":%s 353 %s = %s :%s\n", g_state->server_name, nick, channel, buf); 371 } 372 put_printf(client, obuffer, ":%s 366 %s %s :End of /NAMES list.\n", g_state->server_name, nick, channel); 373 374 return 0; 375 } 376 377 return -1; 378 } 379 380 static int __run_command(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 381 size_t i; 382 int found = 0; 383 384 for (i = 0; g_commands[i].name != NULL; i++) { 385 if ( !strcasecmp(g_commands[i].name, cmd) ) { 386 found = 1; 387 g_commands[i].func(client, obuffer, cmd, args, text); 388 } 389 } 390 391 if ( !found ) { 392 put_printf(client, obuffer, ":%s 421 %s %s :Unknown command\n", g_state->server_name, get_nick(client), cmd); 393 } 394 395 return 0; 396 } 397 398 static void cb_client_delete(struct roar_notify_core * core, struct roar_event * event, void * userdata) { 399 int * listener; 400 size_t count; 401 struct channel * c; 402 const char * text = g_state->quit_msg; 403 int client = event->target; 404 const char * ufull = get_ufull(client); 405 size_t i; 406 407 (void)core, (void)userdata; 408 409 if ( text == NULL ) 410 text = "Client deleted. Died, kicked or internal error."; 411 412 if ( g_state->quit_msg != NULL ) 413 put_printf(client, NULL, "ERROR :Closing Link: %s (Quit: %s)\n", ufull, text); 414 415 count = get_listener_list(client, NULL, &listener); 416 for (; count; count--, listener++) 417 put_printf(*listener, NULL, ":%s QUIT :Quit: %s\n", ufull, text); 418 419 for (i = 0; i < MAX_CHANNELS; i++) { 420 c = &(g_state->g_channels[i]); 421 422 if ( !c->client_count ) 423 continue; 424 425 if ( !c->clients[client] ) 426 continue; 427 428 c->clients[client] = 0; 429 c->client_count--; 430 431 if ( !c->client_count ) { 432 roar_mm_free(c->name); 433 434 if ( c->topic.text != NULL ) 435 roar_mm_free(c->topic.text); 436 if ( c->topic.user != NULL ) 437 roar_mm_free(c->topic.user); 438 } 439 } 440 441 clients_flush(client); 442 } 443 444 static int set_proto(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) { 445 struct roar_client_server * cs; 446 char * name; 447 448 (void)client, (void)vio, (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara; 449 450 clients_get_server(client, &cs); 451 452 name = ROAR_CLIENT(cs)->name; 453 snprintf(name, sizeof(ROAR_CLIENT(cs)->name), "Client%i~", client); 454 455 /* 456 :ph7.ph.sft NOTICE AUTH :*** Looking up your hostname... 457 :ph7.ph.sft NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead 458 NICK nick 459 USER A B C D 460 :ph7.ph.sft NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead 461 :ph7.ph.sft 002 nick :Your host is ph7.ph.sft, running version Unreal3.2.7 462 :ph7.ph.sft 003 nick :This server was created Tue Aug 28 2007 at 10:02:00 CEST 463 :ph7.ph.sft 004 nick ph7.ph.sft Unreal3.2.7 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj 464 :ph7.ph.sft 005 nick NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 MAXTARGETS=20 WALLCHOPS :are supported by this server 465 :ph7.ph.sft 005 nick WATCH=128 SILENCE=15 MODES=12 CHANTYPES=# PREFIX=(ohv)@%+ CHANMODES=beIqa,kfL,lj,psmntirRcOAQKVCuzNSMTG NETWORK=PH2 CASEMAPPING=ascii EXTBAN=~,cqnr ELIST=MNUCT STATUSMSG=@%+ EXCEPTS INVEX :are supported by this server 466 :ph7.ph.sft 005 nick CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server 467 */ 468 469 put_printf(client, obuffer, 470 ":%s 001 %s :Welcome to the roard based IRC server.\n" 471 ":%s 375 %s :- %s Message of the Day -\n" 472 ":%s 372 %s :- MotD goes here...\n" 473 ":%s 376 %s :End of /MOTD command.\n", 474 g_state->server_name, name, 475 g_state->server_name, name, g_state->server_name, 476 g_state->server_name, name, 477 g_state->server_name, name 478 ); 479 480 __run_command(client, obuffer, "LUSERS", NULL, NULL); 481 482 return 0; 483 } 484 485 static int check_client(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) { 486 char cmd[1024*2]; 487 char * args; 488 char * text; 489 ssize_t len; 490 491 (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara; 492 493 len = roar_vio_read(vio, cmd, sizeof(cmd)-1); 494 if ( len < 1 ) { 495 clients_delete(client); 496 return -1; 497 } 498 499 cmd[len] = 0; 500 501 strip_nl(cmd); 502 503 ROAR_DBG("check_client(client=%i, vio=?): cmd=\"%s\"", client, cmd); 504 505 if ( cmd[0] == 0 ) 506 return 0; 507 508 args = strstr(cmd, " "); 509 510 if ( args != NULL ) { 511 *args = 0; 512 args++; 513 if ( *args == ':' ) { 514 text = args + 1; 515 args = NULL; 516 } else { 517 text = strstr(args, " :"); 518 if ( text != NULL ) { 519 *text = 0; 520 text += 2; 521 } 522 } 523 } else { 524 text = NULL; 525 } 526 527 __run_command(client, obuffer, cmd, args, text); 528 529 return 0; 530 } 531 532 // commands: 533 static int on_nick(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 534 char * nick = get_nick(client); 535 int * listener; 536 size_t count; 537 const char * ufull; 538 539 (void)cmd, (void)text; 540 541 if ( args != NULL && args[0] != 0 && is_valid_name(args) && strlen(args) < ROAR_BUFFER_NAME ) { 542 if ( get_client_by_nick(args) != -1 ) { 543 put_printf(client, obuffer, ":%s 433 %s %s :Nickname is already in use.\n", g_state->server_name, nick, args); 544 } else { 545 ufull = get_ufull(client); 546 put_printf(client, obuffer, ":%s NICK :%s\n", ufull, args); 547 count = get_listener_list(client, NULL, &listener); 548 for (; count; count--, listener++) 549 if ( *listener != client ) 550 put_printf(*listener, NULL, ":%s NICK :%s\n", ufull, args); 551 552 strcpy(nick, args); 553 } 554 } else { 555 put_printf(client, obuffer, ":%s 432 %s %s :Erroneous Nickname: Illegal characters\n", g_state->server_name, nick, args); 556 } 557 558 return 0; 559 } 560 561 static int on_user(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 562 (void)client, (void)obuffer, (void)cmd, (void)args, (void)text; 563 return 0; 564 } 565 566 static int on_quit(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 567 int ret; 568 569 (void)obuffer, (void)cmd, (void)args; 570 571 if ( text == NULL ) 572 text = "... have a cuddle ..."; 573 574 g_state->quit_msg = text; 575 ret = clients_delete(client); 576 g_state->quit_msg = NULL; 577 578 return ret; 579 } 580 581 static int on_ping(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 582 (void)cmd, (void)args; 583 584 put_printf(client, obuffer, "PONG :%s\n", text); 585 586 return 0; 587 } 588 589 static int on_lusers(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 590 const char * clientnick = get_nick(client); 591 size_t i; 592 size_t numchans = 0; 593 594 (void)cmd, (void)args, (void)text; 595 596 /* 597 :v0.fellig.org 251 nick :There are 9 users and 11 invisible on 1 servers 598 599 :v0.fellig.org 252 nick 1 :operator(s) online 600 601 :v0.fellig.org 254 nick 16 :channels formed 602 :v0.fellig.org 255 nick :I have 20 clients and 0 servers 603 :v0.fellig.org 265 nick :Current Local Users: 20 Max: 52 604 :v0.fellig.org 266 nick :Current Global Users: 20 Max: 22 605 */ 606 607 for (i = 0; i < MAX_CHANNELS; i++) { 608 if ( !g_state->g_channels[i].client_count ) 609 continue; 610 numchans++; 611 } 612 613 put_printf(client, obuffer, ":%s 251 %s :There are %zu users and 0 invisible on 1 servers\n", 614 g_state->server_name, clientnick, counters_get(cur, clients)); 615 put_printf(client, obuffer, ":%s 254 %s %zu :channels formed\n", 616 g_state->server_name, clientnick, numchans); 617 put_printf(client, obuffer, ":%s 255 %s :I have %zu clients and 0 servers\n", 618 g_state->server_name, clientnick, counters_get(cur, clients)); 619 put_printf(client, obuffer, ":%s 265 %s :Current Local Users: %zu Max: <unknown>\n", 620 g_state->server_name, clientnick, counters_get(cur, clients)); 621 put_printf(client, obuffer, ":%s 266 %s :Current Global Users: %zu Max: <unknown>\n", 622 g_state->server_name, clientnick, counters_get(cur, clients)); 623 624 return 0; 625 } 626 627 static int on_whois(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 628 const char * clientnick = get_nick(client); 629 const char * tnick = args; 630 int tclient; 631 632 (void)cmd, (void)text; 633 634 /* 635 :ph7.ph.sft 317 nick phi 131 1322456381 :seconds idle, signon time 636 */ 637 638 if ( (tclient = get_client_by_nick(tnick)) == -1 ) { 639 put_printf(client, obuffer, ":%s 401 %s %s :No such nick/channel\n", g_state->server_name, clientnick, tnick); 640 } else { 641 put_printf(client, obuffer, ":%s 311 %s %s %s %s * :%s\n", g_state->server_name, clientnick, tnick, 642 get_ident(tclient), get_node(tclient), get_realname(tclient)); 643 put_printf(client, obuffer, ":%s 312 %s %s %s :%s\n", g_state->server_name, clientnick, tnick, g_state->server_name, g_state->server_fullname); 644 } 645 put_printf(client, obuffer, ":%s 318 %s %s :End of /WHOIS list.\n", g_state->server_name, clientnick, tnick); 646 647 return 0; 648 } 649 650 static int on_privmsg(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 651 const char * ufull = get_ufull(client); 652 int * listener; 653 size_t count; 654 char * next; 655 int tmp; 656 657 if ( args == NULL || text == NULL ) 658 return -1; 659 660 if ( text[0] == 0 ) 661 return 0; 662 663 while (args != NULL) { 664 next = strstr(args, ","); 665 if ( next != NULL ) { 666 *next = 0; 667 next++; 668 } 669 670 if ( args[0] == '#' ) { 671 count = get_listener_list(client, args, &listener); 672 for (; count; count--, listener++) 673 if ( *listener != client ) 674 put_printf(*listener, NULL, ":%s %s %s :%s\n", ufull, cmd, args, text); 675 } else { 676 if ( (tmp = get_client_by_nick(args)) == -1 ) { 677 put_printf(client, obuffer, ":%s 401 %s %s :No such nick/channel\n", g_state->server_name, get_nick(client), args); 678 } else { 679 put_printf(tmp, NULL, ":%s %s %s :%s\n", ufull, cmd, args, text); 680 } 681 } 682 683 args = next; 684 } 685 686 return 0; 687 } 688 689 690 static int on_list(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 691 const char * clientnick = get_nick(client); 692 struct channel * c; 693 size_t i; 694 695 (void)cmd, (void)args, (void)text; 696 697 put_printf(client, obuffer, ":%s 321 %s Channel :Users Name\n", g_state->server_name, clientnick); 698 699 for (i = 0; i < MAX_CHANNELS; i++) { 700 c = &(g_state->g_channels[i]); 701 if ( !c->client_count ) 702 continue; 703 704 put_printf(client, obuffer, ":%s 322 %s %s %zu :[+] %s\n", 705 g_state->server_name, clientnick, c->name, c->client_count, c->topic.text == NULL ? "" : c->topic.text); 706 } 707 708 put_printf(client, obuffer, ":%s 323 %s :End of /LIST\n", g_state->server_name, clientnick); 709 710 return 0; 711 } 712 713 static int on_join(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 714 struct channel * c; 715 const char * ufull = get_ufull(client); 716 int * listener; 717 size_t count; 718 const char * nick; 719 720 (void)cmd, (void)text; 721 722 if ( args == NULL ) 723 return -1; 724 725 if ( do_join(client, args) != 0 ) { 726 return -1; 727 } 728 729 count = get_listener_list(client, args, &listener); 730 for (; count; count--, listener++) 731 put_printf(*listener, NULL, ":%s JOIN :%s\n", ufull, args); 732 733 c = get_channel(args); 734 735 if ( c->topic.text != NULL ) { 736 nick = get_nick(client); 737 put_printf(client, obuffer, ":%s 332 %s %s :%s\n" 738 ":%s 333 %s %s %s %li\n", 739 g_state->server_name, nick, c->name, c->topic.text, 740 g_state->server_name, nick, c->name, c->topic.user, (long int)c->topic.ts 741 ); 742 } 743 744 do_names(client, obuffer, args); 745 746 return 0; 747 } 748 749 static int on_part(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 750 const char * ufull = get_ufull(client); 751 int * listener; 752 size_t count; 753 754 (void)obuffer, (void)cmd; 755 756 if ( args == NULL ) 757 return -1; 758 759 if ( text == NULL ) 760 text = "Dejoined."; 761 762 count = get_listener_list(client, args, &listener); 763 for (; count; count--, listener++) 764 put_printf(*listener, NULL, ":%s PART %s :%s\n", ufull, args, text); 765 766 do_part(client, args); 767 768 return 0; 769 } 770 771 static int on_names(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 772 (void)cmd, (void)text; 773 774 if ( args == NULL ) 775 return -1; 776 777 return do_names(client, obuffer, args); 778 } 779 780 static int on_topic(int client, struct roar_buffer ** obuffer, const char * cmd, char * args, char * text) { 781 struct channel * c; 782 const char * ufull = get_ufull(client); 783 int * listener; 784 size_t count; 785 char * nick = get_nick(client); 786 787 (void)obuffer, (void)cmd; 788 789 if ( args == NULL ) 790 return -1; 791 792 c = get_channel(args); 793 794 if ( c == NULL ) 795 return -1; 796 797 if ( !c->clients[client] ) { 798 return -1; 799 } 800 801 if ( c->topic.text != NULL ) 802 roar_mm_free(c->topic.text); 803 if ( c->topic.user != NULL ) 804 roar_mm_free(c->topic.user); 805 806 c->topic.text = NULL; 807 c->topic.user = roar_mm_strdup(nick); 808 c->topic.ts = time(NULL); 809 810 if ( text != NULL ) 811 c->topic.text = roar_mm_strdup(text); 812 813 if ( text == NULL ) 814 text = ""; 815 816 count = get_listener_list(client, c->name, &listener); 817 for (; count; count--, listener++) 818 put_printf(*listener, NULL, ":%s TOPIC %s :%s\n", ufull, c->name, text); 819 820 return 0; 821 } 822 823 static const struct command g_commands[] = { 84 824 {"NICK", on_nick}, 85 825 {"USER", on_user}, … … 98 838 }; 99 839 100 static int is_valid_name (const char * name) {101 register char c;102 103 for (; (c = *name) != 0; name++) {104 if ( !(isalnum(c) || c == '-' || c == '_') )105 return 0;106 }107 108 return 1;109 }110 111 static void strip_nl(char * str) {112 register char c;113 114 for (; (c = *str) != 0; str++) {115 if ( c == '\r' || c == '\n' ) {116 *str = 0;117 return;118 }119 }120 }121 122 static char * get_nick(int client) {123 struct roar_client * c;124 clients_get(client, &c);125 return c->name;126 }127 128 static const char * get_ident(int client) {129 static char buf[80];130 struct roar_client * c;131 clients_get(client, &c);132 133 if ( c->uid == -1 ) {134 buf[0] = '~';135 buf[1] = 0;136 } else {137 snprintf(buf, sizeof(buf)-1, "uid%i~", c->uid);138 buf[sizeof(buf)-1] = 0;139 }140 141 return buf;142 }143 144 static const char * get_node(int client) {145 struct roar_client * c;146 static char buf_nnode[80];147 char * nnode;148 149 clients_get(client, &c);150 151 roar_nnode_to_str(&(c->nnode), buf_nnode, sizeof(buf_nnode));152 153 nnode = strstr(buf_nnode, ": ");154 if ( nnode == NULL ) {155 nnode = "unknown~";156 } else {157 nnode += 2;158 }159 160 return nnode;161 }162 163 static const char * get_ufull(int client) {164 struct roar_client * c;165 static char buf[80];166 const char * ident = get_ident(client);167 const char * nnode = get_node(client);168 169 clients_get(client, &c);170 171 snprintf(buf, sizeof(buf)-1, "%s!%s@%s", c->name, ident, nnode);172 173 buf[sizeof(buf)-1] = 0;174 175 return buf;176 }177 178 static const char * get_realname(int client) {179 (void)client;180 return "(no realname)";181 }182 183 static int get_client_by_nick(const char * nick) {184 struct roar_client * c;185 int i;186 187 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {188 if ( clients_get(i, &c) != 0 )189 continue;190 191 if ( !!strcasecmp(c->name, nick) )192 continue;193 194 return i;195 }196 197 return -1;198 }199 200 static struct channel * get_channel(const char * name) {201 struct channel * c;202 size_t i;203 204 for (i = 0; i < MAX_CHANNELS; i++) {205 c = &(g_state->g_channels[i]);206 207 if ( !c->client_count )208 continue;209 210 if ( !!strcasecmp(c->name, name) )211 continue;212 213 return c;214 }215 216 return NULL;217 }218 219 static size_t get_listener_list(int client, const char * channel, int ** listener) {220 struct channel * c;221 static int clients[ROAR_CLIENTS_MAX];222 size_t ret = 0;223 size_t i, k;224 int j;225 int found;226 227 for (i = 0; i < MAX_CHANNELS; i++) {228 c = &(g_state->g_channels[i]);229 230 if ( !c->client_count )231 continue;232 233 if ( c->clients[client] < 1 )234 continue;235 236 if ( channel != NULL && !!strcasecmp(c->name, channel) )237 continue;238 239 for (j = 0; j < ROAR_CLIENTS_MAX; j++) {240 if ( c->clients[j] > 0 ) {241 found = 0;242 for (k = 0; k < ret; k++) {243 if ( clients[k] == j ) {244 found = 1;245 }246 }247 if ( !found ) {248 clients[ret] = j;249 ret++;250 }251 }252 }253 }254 255 *listener = clients;256 257 return ret;258 }259 260 static void put_printf(int client, const char *format, ...) {261 va_list ap;262 struct roar_buffer * buf;263 size_t len = 2048;264 void * data;265 int ret;266 267 if ( roar_buffer_new_data(&buf, len, &data) == -1 )268 return;269 270 va_start(ap, format);271 ret = vsnprintf(data, len-1, format, ap);272 va_end(ap);273 274 if ( roar_buffer_set_len(buf, strlen(data)) == -1 ) {275 roar_buffer_free(buf);276 return;277 }278 279 clients_add_output(client, &buf);280 }281 282 static int do_join(int client, const char * channel) {283 struct channel * c = NULL;284 size_t i;285 286 if ( channel[0] != '#' )287 return -1;288 289 if ( !is_valid_name(channel+1) )290 return -1;291 292 for (i = 0; i < MAX_CHANNELS; i++) {293 if ( !g_state->g_channels[i].client_count )294 continue;295 296 if ( !!strcasecmp(g_state->g_channels[i].name, channel) )297 continue;298 299 c = &(g_state->g_channels[i]);300 break;301 }302 303 if ( c == NULL ) {304 for (i = 0; i < MAX_CHANNELS; i++) {305 if ( g_state->g_channels[i].client_count )306 continue;307 308 c = &(g_state->g_channels[i]);309 break;310 }311 312 if ( c == NULL )313 return -1;314 315 memset(c, 0, sizeof(*c));316 317 c->name = roar_mm_strdup(channel);318 }319 320 if ( c->clients[client] )321 return -1;322 323 c->clients[client] = 1;324 c->client_count++;325 326 return 0;327 }328 329 static int do_part(int client, const char * channel) {330 struct channel * c = NULL;331 size_t i;332 333 for (i = 0; i < MAX_CHANNELS; i++) {334 if ( !g_state->g_channels[i].client_count )335 continue;336 337 if ( !!strcasecmp(g_state->g_channels[i].name, channel) )338 continue;339 340 if ( !g_state->g_channels[i].clients[client] )341 return -1;342 343 c = &(g_state->g_channels[i]);344 break;345 }346 347 c->clients[client] = 0;348 c->client_count--;349 350 if ( !c->client_count ) {351 roar_mm_free(c->name);352 353 if ( c->topic.text != NULL )354 roar_mm_free(c->topic.text);355 if ( c->topic.user != NULL )356 roar_mm_free(c->topic.user);357 }358 359 return 0;360 }361 362 static int do_names(int client, const char * channel) {363 const char * nick = get_nick(client);364 size_t i;365 char buf[256];366 size_t len, offset;367 char * c_nick;368 int j;369 370 for (i = 0; i < MAX_CHANNELS; i++) {371 if ( !g_state->g_channels[i].client_count )372 continue;373 374 if ( !!strcasecmp(g_state->g_channels[i].name, channel) )375 continue;376 377 offset = 0;378 379 for (j = 0; j < ROAR_CLIENTS_MAX; j++) {380 if ( g_state->g_channels[i].clients[j] == 0 )381 continue;382 383 c_nick = get_nick(j);384 len = strlen(c_nick);385 if ( (offset + len + 3) > sizeof(buf) ) {386 buf[offset] = 0;387 put_printf(client, ":%s 353 %s = %s :%s\n", g_state->server_name, nick, channel, buf);388 offset = 0;389 }390 391 memcpy(buf + offset, c_nick, len);392 offset += len;393 buf[offset] = ' ';394 offset++;395 buf[offset] = 0;396 }397 398 if ( offset ) {399 buf[offset] = 0;400 put_printf(client, ":%s 353 %s = %s :%s\n", g_state->server_name, nick, channel, buf);401 }402 put_printf(client, ":%s 366 %s %s :End of /NAMES list.\n", g_state->server_name, nick, channel);403 404 return 0;405 }406 407 return -1;408 }409 410 static void cb_client_delete(struct roar_notify_core * core, struct roar_event * event, void * userdata) {411 int * listener;412 size_t count;413 struct channel * c;414 const char * text = g_state->quit_msg;415 int client = event->target;416 const char * ufull = get_ufull(client);417 size_t i;418 419 (void)core, (void)userdata;420 421 if ( text == NULL )422 text = "Client deleted. Died, kicked or internal error.";423 424 if ( g_state->quit_msg != NULL )425 put_printf(client, "ERROR :Closing Link: %s (Quit: %s)\n", ufull, text);426 427 count = get_listener_list(client, NULL, &listener);428 for (; count; count--, listener++)429 put_printf(*listener, ":%s QUIT :Quit: %s\n", ufull, text);430 431 for (i = 0; i < MAX_CHANNELS; i++) {432 c = &(g_state->g_channels[i]);433 434 if ( !c->client_count )435 continue;436 437 if ( !c->clients[client] )438 continue;439 440 c->clients[client] = 0;441 c->client_count--;442 443 if ( !c->client_count ) {444 roar_mm_free(c->name);445 446 if ( c->topic.text != NULL )447 roar_mm_free(c->topic.text);448 if ( c->topic.user != NULL )449 roar_mm_free(c->topic.user);450 }451 }452 453 clients_flush(client);454 }455 456 static int set_proto(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {457 struct roar_client_server * cs;458 char * name;459 460 (void)client, (void)vio, (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;461 462 clients_get_server(client, &cs);463 464 name = ROAR_CLIENT(cs)->name;465 snprintf(name, sizeof(ROAR_CLIENT(cs)->name), "Client%i~", client);466 467 /*468 :ph7.ph.sft NOTICE AUTH :*** Looking up your hostname...469 :ph7.ph.sft NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead470 NICK nick471 USER A B C D472 :ph7.ph.sft NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead473 :ph7.ph.sft 002 nick :Your host is ph7.ph.sft, running version Unreal3.2.7474 :ph7.ph.sft 003 nick :This server was created Tue Aug 28 2007 at 10:02:00 CEST475 :ph7.ph.sft 004 nick ph7.ph.sft Unreal3.2.7 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj476 :ph7.ph.sft 005 nick NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 MAXTARGETS=20 WALLCHOPS :are supported by this server477 :ph7.ph.sft 005 nick WATCH=128 SILENCE=15 MODES=12 CHANTYPES=# PREFIX=(ohv)@%+ CHANMODES=beIqa,kfL,lj,psmntirRcOAQKVCuzNSMTG NETWORK=PH2 CASEMAPPING=ascii EXTBAN=~,cqnr ELIST=MNUCT STATUSMSG=@%+ EXCEPTS INVEX :are supported by this server478 :ph7.ph.sft 005 nick CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server479 */480 481 put_printf(client,482 ":%s 001 %s :Welcome to the roard based IRC server.\n"483 ":%s 375 %s :- %s Message of the Day -\n"484 ":%s 372 %s :- MotD goes here...\n"485 ":%s 376 %s :End of /MOTD command.\n",486 g_state->server_name, name,487 g_state->server_name, name, g_state->server_name,488 g_state->server_name, name,489 g_state->server_name, name490 );491 492 on_lusers(client, NULL, NULL, NULL);493 494 return 0;495 }496 497 static int check_client(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {498 char cmd[1024*2];499 char * args;500 char * text;501 ssize_t len;502 size_t i;503 int found = 0;504 505 (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;506 507 len = roar_vio_read(vio, cmd, sizeof(cmd)-1);508 if ( len < 1 ) {509 clients_delete(client);510 return -1;511 }512 513 cmd[len] = 0;514 515 strip_nl(cmd);516 517 ROAR_DBG("check_client(client=%i, vio=?): cmd=\"%s\"", client, cmd);518 519 if ( cmd[0] == 0 )520 return 0;521 522 args = strstr(cmd, " ");523 524 if ( args != NULL ) {525 *args = 0;526 args++;527 if ( *args == ':' ) {528 text = args + 1;529 args = NULL;530 } else {531 text = strstr(args, " :");532 if ( text != NULL ) {533 *text = 0;534 text += 2;535 }536 }537 } else {538 text = NULL;539 }540 541 for (i = 0; g_commands[i].name != NULL; i++) {542 if ( !strcasecmp(g_commands[i].name, cmd) ) {543 found = 1;544 g_commands[i].func(client, cmd, args, text);545 }546 }547 548 if ( !found ) {549 put_printf(client, ":%s 421 %s %s :Unknown command\n", g_state->server_name, get_nick(client), cmd);550 }551 552 return 0;553 }554 555 // commands:556 static int on_nick(int client, const char * cmd, char * args, char * text) {557 char * nick = get_nick(client);558 int * listener;559 size_t count;560 const char * ufull;561 562 (void)cmd, (void)text;563 564 if ( args != NULL && args[0] != 0 && is_valid_name(args) && strlen(args) < ROAR_BUFFER_NAME ) {565 if ( get_client_by_nick(args) != -1 ) {566 put_printf(client, ":%s 433 %s %s :Nickname is already in use.\n", g_state->server_name, nick, args);567 } else {568 ufull = get_ufull(client);569 put_printf(client, ":%s NICK :%s\n", ufull, args);570 count = get_listener_list(client, NULL, &listener);571 for (; count; count--, listener++)572 if ( *listener != client )573 put_printf(*listener, ":%s NICK :%s\n", ufull, args);574 575 strcpy(nick, args);576 }577 } else {578 put_printf(client, ":%s 432 %s %s :Erroneous Nickname: Illegal characters\n", g_state->server_name, nick, args);579 }580 581 return 0;582 }583 584 static int on_user(int client, const char * cmd, char * args, char * text) {585 (void)client, (void)cmd, (void)args, (void)text;586 return 0;587 }588 589 static int on_quit(int client, const char * cmd, char * args, char * text) {590 int ret;591 592 (void)cmd, (void)args;593 594 if ( text == NULL )595 text = "... have a cuddle ...";596 597 g_state->quit_msg = text;598 ret = clients_delete(client);599 g_state->quit_msg = NULL;600 601 return ret;602 }603 604 static int on_ping(int client, const char * cmd, char * args, char * text) {605 (void)cmd, (void)args;606 607 put_printf(client, "PONG :%s\n", text);608 609 return 0;610 }611 612 static int on_lusers(int client, const char * cmd, char * args, char * text) {613 const char * clientnick = get_nick(client);614 size_t i;615 size_t numchans = 0;616 617 (void)cmd, (void)args, (void)text;618 619 /*620 :v0.fellig.org 251 nick :There are 9 users and 11 invisible on 1 servers621 622 :v0.fellig.org 252 nick 1 :operator(s) online623 624 :v0.fellig.org 254 nick 16 :channels formed625 :v0.fellig.org 255 nick :I have 20 clients and 0 servers626 :v0.fellig.org 265 nick :Current Local Users: 20 Max: 52627 :v0.fellig.org 266 nick :Current Global Users: 20 Max: 22628 */629 630 for (i = 0; i < MAX_CHANNELS; i++) {631 if ( !g_state->g_channels[i].client_count )632 continue;633 numchans++;634 }635 636 put_printf(client, ":%s 251 %s :There are %zu users and 0 invisible on 1 servers\n",637 g_state->server_name, clientnick, counters_get(cur, clients));638 put_printf(client, ":%s 254 %s %zu :channels formed\n",639 g_state->server_name, clientnick, numchans);640 put_printf(client, ":%s 255 %s :I have %zu clients and 0 servers\n",641 g_state->server_name, clientnick, counters_get(cur, clients));642 put_printf(client, ":%s 265 %s :Current Local Users: %zu Max: <unknown>\n",643 g_state->server_name, clientnick, counters_get(cur, clients));644 put_printf(client, ":%s 266 %s :Current Global Users: %zu Max: <unknown>\n",645 g_state->server_name, clientnick, counters_get(cur, clients));646 647 return 0;648 }649 650 static int on_whois(int client, const char * cmd, char * args, char * text) {651 const char * clientnick = get_nick(client);652 const char * tnick = args;653 int tclient;654 655 (void)cmd, (void)text;656 657 /*658 :ph7.ph.sft 317 nick phi 131 1322456381 :seconds idle, signon time659 */660 661 if ( (tclient = get_client_by_nick(tnick)) == -1 ) {662 put_printf(client, ":%s 401 %s %s :No such nick/channel\n", g_state->server_name, clientnick, tnick);663 } else {664 put_printf(client, ":%s 311 %s %s %s %s * :%s\n", g_state->server_name, clientnick, tnick,665 get_ident(tclient), get_node(tclient), get_realname(tclient));666 put_printf(client, ":%s 312 %s %s %s :%s\n", g_state->server_name, clientnick, tnick, g_state->server_name, g_state->server_fullname);667 }668 put_printf(client, ":%s 318 %s %s :End of /WHOIS list.\n", g_state->server_name, clientnick, tnick);669 670 return 0;671 }672 673 static int on_privmsg(int client, const char * cmd, char * args, char * text) {674 const char * ufull = get_ufull(client);675 int * listener;676 size_t count;677 char * next;678 int tmp;679 680 if ( args == NULL || text == NULL )681 return -1;682 683 if ( text[0] == 0 )684 return 0;685 686 while (args != NULL) {687 next = strstr(args, ",");688 if ( next != NULL ) {689 *next = 0;690 next++;691 }692 693 if ( args[0] == '#' ) {694 count = get_listener_list(client, args, &listener);695 for (; count; count--, listener++)696 if ( *listener != client )697 put_printf(*listener, ":%s %s %s :%s\n", ufull, cmd, args, text);698 } else {699 if ( (tmp = get_client_by_nick(args)) == -1 ) {700 put_printf(client, ":%s 401 %s %s :No such nick/channel\n", g_state->server_name, get_nick(client), args);701 } else {702 put_printf(tmp, ":%s %s %s :%s\n", ufull, cmd, args, text);703 }704 }705 706 args = next;707 }708 709 return 0;710 }711 712 713 static int on_list(int client, const char * cmd, char * args, char * text) {714 const char * clientnick = get_nick(client);715 struct channel * c;716 size_t i;717 718 (void)cmd, (void)args, (void)text;719 720 put_printf(client, ":%s 321 %s Channel :Users Name\n", g_state->server_name, clientnick);721 722 for (i = 0; i < MAX_CHANNELS; i++) {723 c = &(g_state->g_channels[i]);724 if ( !c->client_count )725 continue;726 727 put_printf(client, ":%s 322 %s %s %zu :[+] %s\n",728 g_state->server_name, clientnick, c->name, c->client_count, c->topic.text == NULL ? "" : c->topic.text);729 }730 731 put_printf(client, ":%s 323 %s :End of /LIST\n", g_state->server_name, clientnick);732 733 return 0;734 }735 736 static int on_join(int client, const char * cmd, char * args, char * text) {737 struct channel * c;738 const char * ufull = get_ufull(client);739 int * listener;740 size_t count;741 const char * nick;742 743 (void)cmd, (void)text;744 745 if ( args == NULL )746 return -1;747 748 if ( do_join(client, args) != 0 ) {749 return -1;750 }751 752 count = get_listener_list(client, args, &listener);753 for (; count; count--, listener++)754 put_printf(*listener, ":%s JOIN :%s\n", ufull, args);755 756 c = get_channel(args);757 758 if ( c->topic.text != NULL ) {759 nick = get_nick(client);760 put_printf(client, ":%s 332 %s %s :%s\n"761 ":%s 333 %s %s %s %li\n",762 g_state->server_name, nick, c->name, c->topic.text,763 g_state->server_name, nick, c->name, c->topic.user, (long int)c->topic.ts764 );765 }766 767 do_names(client, args);768 769 return 0;770 }771 772 static int on_part(int client, const char * cmd, char * args, char * text) {773 const char * ufull = get_ufull(client);774 int * listener;775 size_t count;776 777 (void)cmd;778 779 if ( args == NULL )780 return -1;781 782 if ( text == NULL )783 text = "Dejoined.";784 785 count = get_listener_list(client, args, &listener);786 for (; count; count--, listener++)787 put_printf(*listener, ":%s PART %s :%s\n", ufull, args, text);788 789 do_part(client, args);790 791 return 0;792 }793 794 static int on_names(int client, const char * cmd, char * args, char * text) {795 (void)cmd, (void)text;796 797 if ( args == NULL )798 return -1;799 800 return do_names(client, args);801 }802 803 static int on_topic(int client, const char * cmd, char * args, char * text) {804 struct channel * c;805 const char * ufull = get_ufull(client);806 int * listener;807 size_t count;808 char * nick = get_nick(client);809 810 (void)cmd;811 812 if ( args == NULL )813 return -1;814 815 c = get_channel(args);816 817 if ( c == NULL )818 return -1;819 820 if ( !c->clients[client] ) {821 return -1;822 }823 824 if ( c->topic.text != NULL )825 roar_mm_free(c->topic.text);826 if ( c->topic.user != NULL )827 roar_mm_free(c->topic.user);828 829 c->topic.text = NULL;830 c->topic.user = roar_mm_strdup(nick);831 c->topic.ts = time(NULL);832 833 if ( text != NULL )834 c->topic.text = roar_mm_strdup(text);835 836 if ( text == NULL )837 text = "";838 839 count = get_listener_list(client, c->name, &listener);840 for (; count; count--, listener++)841 put_printf(*listener, ":%s TOPIC %s :%s\n", ufull, c->name, text);842 843 return 0;844 }845 846 840 // plugin handling suff: 847 841 static int init(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
Note: See TracChangeset
for help on using the changeset viewer.