source: roaraudio/plugins/roard/protocol-irc.c @ 5309:91102861071a

Last change on this file since 5309:91102861071a was 5309:91102861071a, checked in by phi, 12 years ago

added support for lusers

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