source: roaraudio/plugins/roard/protocol-irc.c @ 5900:3dbe762edefe

Last change on this file since 5900:3dbe762edefe was 5900:3dbe762edefe, checked in by phi, 11 years ago

some movements in direction of getting this more portable

File size: 22.0 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
31struct channel {
32 char * name;
33 struct {
34  char * text;
35  char * user;
36  time_t ts;
37 } topic;
38 size_t client_count;
39 int clients[ROAR_CLIENTS_MAX];
40};
41
42struct state {
43 const char * server_name;
44 const char * server_fullname;
45 const char * quit_msg;
46 struct roar_subscriber * subscription_client_delete;
47 struct channel g_channels[MAX_CHANNELS];
48};
49
50static struct state   g_state_init = {
51 .server_name = "irc.roard",
52 .server_fullname = "RoarAudio roard IRC Server plugin",
53 .quit_msg = NULL,
54 .subscription_client_delete = NULL
55};
56
57static struct state * g_state = &g_state_init;
58
59static const struct command {
60 const char * name;
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[] = {
824 {"NICK", on_nick},
825 {"USER", on_user},
826 {"QUIT", on_quit},
827 {"PING", on_ping},
828 {"LUSERS", on_lusers},
829 {"WHOIS", on_whois},
830 {"PRIVMSG", on_privmsg},
831 {"NOTICE", on_privmsg},
832 {"LIST", on_list},
833 {"JOIN", on_join},
834 {"PART", on_part},
835 {"NAMES", on_names},
836 {"TOPIC", on_topic},
837 {NULL, NULL}
838};
839
840// plugin handling suff:
841static int init(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
842 struct roar_event event;
843
844 (void)para, (void)lib;
845
846 memset(&event, 0, sizeof(event));
847
848 event.event = ROAR_OE_BASICS_DELETE;
849
850 event.emitter = -1;
851 event.target = -1;
852 event.target_type = ROAR_OT_CLIENT;
853
854 memset(g_state->g_channels, 0, sizeof(g_state->g_channels));
855
856 g_state->subscription_client_delete = roar_notify_core_subscribe(NULL, &event, cb_client_delete, NULL);
857
858 return 0;
859}
860
861static int unload(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
862 (void)para, (void)lib;
863
864 roar_notify_core_unsubscribe(NULL, g_state->subscription_client_delete);
865
866 return 0;
867}
868
869static const struct roar_dl_proto proto = {
870 .proto = ROAR_PROTO_IRC,
871 .description = "Internet Relay Chat",
872 .flags = ROAR_DL_PROTO_FLAGS_NONE,
873 .set_proto = set_proto,
874 .unset_proto = NULL,
875 .handle = check_client,
876 .flush = NULL,
877 .flushed = NULL,
878 .status = NULL
879};
880
881static int __reg_proto(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
882 (void)para, (void)lib;
883 ROAR_DL_PLUGIN_REG_FN(ROAR_DL_PROTO_SUBTYPE, proto, ROAR_DL_PROTO_VERSION);
884 return 0;
885}
886
887ROAR_DL_PLUGIN_START(protocol_irc) {
888 ROARD_DL_CHECK_VERSIONS();
889
890 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-irc", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
891 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
892 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
893 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
894 ROAR_DL_PLUGIN_META_DESC("Implementation of the Internet Relay Chat (IRC)");
895
896 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_PROTO, __reg_proto);
897 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_INIT, init);
898 ROAR_DL_PLUGIN_REG_UNLOAD(unload);
899 ROAR_DL_PLUGIN_REG_GLOBAL_DATA(g_state, g_state_init);
900} ROAR_DL_PLUGIN_END
901
902//ll
Note: See TracBrowser for help on using the repository browser.