Changeset 5900:3dbe762edefe in roaraudio


Ignore:
Timestamp:
04/14/13 16:01:18 (11 years ago)
Author:
phi
Branch:
default
Phase:
public
Message:

some movements in direction of getting this more portable

File:
1 edited

Legend:

Unmodified
Added
Removed
  • plugins/roard/protocol-irc.c

    r5899 r5900  
    2929#define MAX_CHANNELS 8 
    3030 
    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  
    5231struct channel { 
    5332 char * name; 
     
    8059static const struct command { 
    8160 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 
     64static 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 
     75static 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 
     86static char * get_nick(int client) { 
     87 struct roar_client * c; 
     88 clients_get(client, &c); 
     89 return c->name; 
     90} 
     91 
     92static 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 
     108static 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 
     127static 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 
     142static const char * get_realname(int client) { 
     143 (void)client; 
     144 return "(no realname)"; 
     145} 
     146 
     147static 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 
     164static 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 
     183static 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 
     224static 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 
     252static 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 
     299static 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 
     332static 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 
     380static 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 
     398static 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 
     444static 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 
     458NICK nick 
     459USER 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 
     485static 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: 
     533static 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 
     561static 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 
     566static 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 
     581static 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 
     589static 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 
     627static 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 
     650static 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 
     690static 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 
     713static 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 
     749static 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 
     771static 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 
     780static 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 
     823static const struct command g_commands[] = { 
    84824 {"NICK", on_nick}, 
    85825 {"USER", on_user}, 
     
    98838}; 
    99839 
    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 instead 
    470 NICK nick 
    471 USER A B C D 
    472 :ph7.ph.sft NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead 
    473 :ph7.ph.sft 002 nick :Your host is ph7.ph.sft, running version Unreal3.2.7 
    474 :ph7.ph.sft 003 nick :This server was created Tue Aug 28 2007 at 10:02:00 CEST 
    475 :ph7.ph.sft 004 nick ph7.ph.sft Unreal3.2.7 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj 
    476 :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 
    477 :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 
    478 :ph7.ph.sft 005 nick CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server 
    479 */ 
    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, name 
    490  ); 
    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 servers 
    621  
    622 :v0.fellig.org 252 nick 1 :operator(s) online 
    623  
    624 :v0.fellig.org 254 nick 16 :channels formed 
    625 :v0.fellig.org 255 nick :I have 20 clients and 0 servers 
    626 :v0.fellig.org 265 nick :Current Local Users: 20  Max: 52 
    627 :v0.fellig.org 266 nick :Current Global Users: 20  Max: 22 
    628 */ 
    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 time 
    659 */ 
    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.ts 
    764   ); 
    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  
    846840// plugin handling suff: 
    847841static int init(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) { 
Note: See TracChangeset for help on using the changeset viewer.