source: roaraudio/plugins/roard/protocol-irc.c @ 5760:8ecfc415d2ab

Last change on this file since 5760:8ecfc415d2ab was 5760:8ecfc415d2ab, checked in by phi, 11 years ago

corrected handling of notify in case client died.

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