source: roaraudio/plugins/roard/protocol-irc.c @ 5899:4e7e80f39536

Last change on this file since 5899:4e7e80f39536 was 5899:4e7e80f39536, checked in by phi, 11 years ago

use a instance-local global state

File size: 21.9 KB
Line 
1//irc.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2013
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include <roard/include/roard.h>
27#include <ctype.h>
28
29#define MAX_CHANNELS 8
30
31static int on_nick(int client, const char * cmd, char * args, char * text);
32static int on_user(int client, const char * cmd, char * args, char * text);
33static int on_quit(int client, const char * cmd, char * args, char * text);
34static int on_ping(int client, const char * cmd, char * args, char * text);
35static int on_lusers(int client, const char * cmd, char * args, char * text);
36static int on_whois(int client, const char * cmd, char * args, char * text);
37static int on_privmsg(int client, const char * cmd, char * args, char * text);
38
39static int on_list(int client, const char * cmd, char * args, char * text);
40static int on_join(int client, const char * cmd, char * args, char * text);
41static int on_part(int client, const char * cmd, char * args, char * text);
42static int on_names(int client, const char * cmd, char * args, char * text);
43
44static int on_topic(int client, const char * cmd, char * args, char * text);
45
46static int do_join(int client, const char * channel);
47static int do_part(int client, const char * channel);
48static int do_names(int client, const char * channel);
49
50static void cb_client_delete(struct roar_notify_core * core, struct roar_event * event, void * userdata);
51
52struct channel {
53 char * name;
54 struct {
55  char * text;
56  char * user;
57  time_t ts;
58 } topic;
59 size_t client_count;
60 int clients[ROAR_CLIENTS_MAX];
61};
62
63struct state {
64 const char * server_name;
65 const char * server_fullname;
66 const char * quit_msg;
67 struct roar_subscriber * subscription_client_delete;
68 struct channel g_channels[MAX_CHANNELS];
69};
70
71static struct state   g_state_init = {
72 .server_name = "irc.roard",
73 .server_fullname = "RoarAudio roard IRC Server plugin",
74 .quit_msg = NULL,
75 .subscription_client_delete = NULL
76};
77
78static struct state * g_state = &g_state_init;
79
80static const struct command {
81 const char * name;
82 int (*func)(int client, const char * cmd, char * args, char * text);
83} g_commands[] = {
84 {"NICK", on_nick},
85 {"USER", on_user},
86 {"QUIT", on_quit},
87 {"PING", on_ping},
88 {"LUSERS", on_lusers},
89 {"WHOIS", on_whois},
90 {"PRIVMSG", on_privmsg},
91 {"NOTICE", on_privmsg},
92 {"LIST", on_list},
93 {"JOIN", on_join},
94 {"PART", on_part},
95 {"NAMES", on_names},
96 {"TOPIC", on_topic},
97 {NULL, NULL}
98};
99
100static 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
111static 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
122static char * get_nick(int client) {
123 struct roar_client * c;
124 clients_get(client, &c);
125 return c->name;
126}
127
128static 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
144static 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
163static 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
178static const char * get_realname(int client) {
179 (void)client;
180 return "(no realname)";
181}
182
183static 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
200static 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
219static 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
260static 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
282static 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
329static 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
362static 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
410static 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
456static 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
470NICK nick
471USER 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
497static 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:
556static 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
584static 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
589static 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
604static 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
612static 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
650static 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
673static 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
713static 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
736static 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
772static 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
794static 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
803static 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// plugin handling suff:
847static int init(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
848 struct roar_event event;
849
850 (void)para, (void)lib;
851
852 memset(&event, 0, sizeof(event));
853
854 event.event = ROAR_OE_BASICS_DELETE;
855
856 event.emitter = -1;
857 event.target = -1;
858 event.target_type = ROAR_OT_CLIENT;
859
860 memset(g_state->g_channels, 0, sizeof(g_state->g_channels));
861
862 g_state->subscription_client_delete = roar_notify_core_subscribe(NULL, &event, cb_client_delete, NULL);
863
864 return 0;
865}
866
867static int unload(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
868 (void)para, (void)lib;
869
870 roar_notify_core_unsubscribe(NULL, g_state->subscription_client_delete);
871
872 return 0;
873}
874
875static const struct roar_dl_proto proto = {
876 .proto = ROAR_PROTO_IRC,
877 .description = "Internet Relay Chat",
878 .flags = ROAR_DL_PROTO_FLAGS_NONE,
879 .set_proto = set_proto,
880 .unset_proto = NULL,
881 .handle = check_client,
882 .flush = NULL,
883 .flushed = NULL,
884 .status = NULL
885};
886
887static int __reg_proto(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
888 (void)para, (void)lib;
889 ROAR_DL_PLUGIN_REG_FN(ROAR_DL_PROTO_SUBTYPE, proto, ROAR_DL_PROTO_VERSION);
890 return 0;
891}
892
893ROAR_DL_PLUGIN_START(protocol_irc) {
894 ROARD_DL_CHECK_VERSIONS();
895
896 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-irc", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
897 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
898 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
899 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
900 ROAR_DL_PLUGIN_META_DESC("Implementation of the Internet Relay Chat (IRC)");
901
902 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_PROTO, __reg_proto);
903 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_INIT, init);
904 ROAR_DL_PLUGIN_REG_UNLOAD(unload);
905 ROAR_DL_PLUGIN_REG_GLOBAL_DATA(g_state, g_state_init);
906} ROAR_DL_PLUGIN_END
907
908//ll
Note: See TracBrowser for help on using the repository browser.