/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/handle_irc.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/handle_irc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 #define CONNECTION_INTERNAL_ACCESS
19 #include "common/setup_before.h"
20 #include "common/util.h" //amadeo: needed for strstart
21 #ifdef STDC_HEADERS
22 # include <stdlib.h>
23 #else
24 # ifdef HAVE_MALLOC_H
25 # include <malloc.h>
26 # endif
27 #endif
28 #ifdef HAVE_STRING_H
29 # include <string.h>
30 #else
31 # ifdef HAVE_STRINGS_H
32 # include <strings.h>
33 # endif
34 # ifdef HAVE_MEMORY_H
35 # include <memory.h>
36 # endif
37 #endif
38 #include "compat/strdup.h"
39 #include "compat/strcasecmp.h"
40 #include <errno.h>
41 #include "compat/strerror.h"
42 #include "common/irc_protocol.h"
43 #include "common/packet.h"
44 #include "common/eventlog.h"
45 #include "connection.h"
46 #include "common/bn_type.h"
47 #include "common/field_sizes.h"
48 #include "common/addr.h"
49 #include "common/version.h"
50 #include "common/queue.h"
51 #include "common/list.h"
52 #include "common/bnethash.h"
53 #include "common/bnethashconv.h"
54 #include "message.h"
55 #include "account.h"
56 #include "account_wrap.h"
57 #include "channel.h"
58 #include "irc.h"
59 #include "prefs.h"
60 #include "tick.h"
61 #include "timer.h"
62 #include "server.h"
63 #include "command.h"
64 #include "handle_irc.h"
65 #include "topic.h"
66 #include "command_groups.h"
67 #include "common/tag.h"
68 #include "common/xalloc.h"
69 #include "ctype.h"
70 #include "common/setup_after.h"
71
72 typedef int (* t_irc_command)(t_connection * conn, int numparams, char ** params, char * text);
73
74 typedef struct {
75 const char * irc_command_string;
76 t_irc_command irc_command_handler;
77 } t_irc_command_table_row;
78
79 static int _handle_nick_command(t_connection * conn, int numparams, char ** params, char * text);
80 static int _handle_user_command(t_connection * conn, int numparams, char ** params, char * text);
81 static int _handle_ping_command(t_connection * conn, int numparams, char ** params, char * text);
82 static int _handle_pong_command(t_connection * conn, int numparams, char ** params, char * text);
83 static int _handle_pass_command(t_connection * conn, int numparams, char ** params, char * text);
84 static int _handle_privmsg_command(t_connection * conn, int numparams, char ** params, char * text);
85 static int _handle_notice_command(t_connection * conn, int numparams, char ** params, char * text);
86 static int _handle_quit_command(t_connection * conn, int numparams, char ** params, char * text);
87
88
89 static int _handle_who_command(t_connection * conn, int numparams, char ** params, char * text);
90 static int _handle_list_command(t_connection * conn, int numparams, char ** params, char * text);
91 static int _handle_topic_command(t_connection * conn, int numparams, char ** params, char * text);
92 static int _handle_join_command(t_connection * conn, int numparams, char ** params, char * text);
93 static int _handle_names_command(t_connection * conn, int numparams, char ** params, char * text);
94 static int _handle_mode_command(t_connection * conn, int numparams, char ** params, char * text);
95 static int _handle_userhost_command(t_connection * conn, int numparams, char ** params, char * text);
96 static int _handle_ison_command(t_connection * conn, int numparams, char ** params, char * text);
97 static int _handle_whois_command(t_connection * conn, int numparams, char ** params, char * text);
98
99
100 /* state connected handlers */
101 static const t_irc_command_table_row irc_con_command_table[] =
102 {
103 { "NICK" , _handle_nick_command },
104 { "USER" , _handle_user_command },
105 { "PING" , _handle_ping_command },
106 { "PONG" , _handle_pong_command },
107 { "PASS" , _handle_pass_command },
108 { "PRIVMSG" , _handle_privmsg_command },
109 { "NOTICE" , _handle_notice_command },
110 { "QUIT" , _handle_quit_command },
111 { NULL , NULL }
112 };
113
114 /* state log'ed in handlers */
115
116 static const t_irc_command_table_row irc_log_command_table[] =
117 {
118 { "WHO" , _handle_who_command },
119 { "LIST" , _handle_list_command },
120 { "TOPIC" , _handle_topic_command },
121 { "JOIN" , _handle_join_command },
122 { "NAMES" , _handle_names_command },
123 { "MODE" , _handle_mode_command },
124 { "USERHOST" , _handle_userhost_command },
125 { "ISON" , _handle_ison_command },
126 { "WHOIS" , _handle_whois_command },
127 { NULL , NULL }
128 };
129
130
131 static int handle_irc_con_command(t_connection * conn, char const * command, int numparams, char ** params, char * text)
132 {
133 t_irc_command_table_row const *p;
134
135 for (p = irc_con_command_table; p->irc_command_string != NULL; p++)
136 {
137 if (strcasecmp(command, p->irc_command_string)==0)
138 {
139 if (p->irc_command_handler != NULL) return ((p->irc_command_handler)(conn,numparams,params,text));
140 }
141 }
142 return -1;
143 }
144
145 static int handle_irc_log_command(t_connection * conn, char const * command, int numparams, char ** params, char * text)
146 {
147 t_irc_command_table_row const *p;
148
149 for (p = irc_log_command_table; p->irc_command_string != NULL; p++)
150 {
151 if (strcasecmp(command, p->irc_command_string)==0)
152 {
153 if (p->irc_command_handler != NULL) return ((p->irc_command_handler)(conn,numparams,params,text));
154 }
155 }
156 return -1;
157 }
158
159 static int handle_irc_line(t_connection * conn, char const * ircline)
160 { /* [:prefix] <command> [[param1] [param2] ... [paramN]] [:<text>]*/
161 char * line; /* copy of ircline */
162 char * prefix = NULL; /* optional; mostly NULL */
163 char * command; /* mandatory */
164 char ** params = NULL; /* optional (array of params) */
165 char * text = NULL; /* optional */
166 char * bnet_command = NULL; //amadeo: used for battle.net.commands
167 int unrecognized_before = 0;
168 int linelen; //amadeo: counter for stringlenghts
169
170 int numparams = 0;
171 char * tempparams;
172
173 if (!conn) {
174 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
175 return -1;
176 }
177 if (!ircline) {
178 eventlog(eventlog_level_error,__FUNCTION__,"got NULL ircline");
179 return -1;
180 }
181 if (ircline[0] == '\0') {
182 eventlog(eventlog_level_error,__FUNCTION__,"got empty ircline");
183 return -1;
184 }
185 //amadeo: code was sent by some unknown fellow of pvpgn, prevents buffer-overflow for
186 // too long irc-lines
187
188 if (strlen(ircline)>254) {
189 char * tmp = (char *)ircline;
190 eventlog(eventlog_level_warn,__FUNCTION__,"line to long, truncation...");
191 tmp[254]='\0';
192 }
193
194 line = xstrdup(ircline);
195
196 /* split the message */
197 if (line[0] == ':') {
198 /* The prefix is optional and is rarely provided */
199 prefix = line;
200 if (!(command = strchr(line,' '))) {
201 eventlog(eventlog_level_warn,__FUNCTION__,"got malformed line (missing command)");
202 /* FIXME: send message instead of eventlog? */
203 xfree(line);
204 return -1;
205 }
206 *command++ = '\0';
207 } else {
208 /* In most cases command is the first thing on the line */
209 command = line;
210 }
211
212 tempparams = strchr(command,' ');
213 if (tempparams) {
214 int i;
215
216 *tempparams++ = '\0';
217 if (tempparams[0]==':') {
218 text = tempparams+1; /* theres just text, no params. skip the colon */
219 } else {
220 for (i=0;tempparams[i]!='\0';i++) {
221 if ((tempparams[i]==' ')&&(tempparams[i+1]==':')) {
222 text = tempparams+i;
223 *text++ = '\0';
224 text++; /* skip the colon */
225 break; /* text found, stop search */
226 }
227 }
228 params = irc_get_paramelems(tempparams);
229 }
230 }
231
232 if (params) {
233 /* count parameters */
234 for (numparams=0;params[numparams];numparams++);
235 }
236
237 {
238 int i;
239 char paramtemp[MAX_IRC_MESSAGE_LEN*2];
240 int first = 1;
241
242 memset(paramtemp,0,sizeof(paramtemp));
243 for (i=0;((numparams>0)&&(params[i]));i++) {
244 if (!first) strcat(paramtemp," ");
245 strcat(paramtemp,"\"");
246 strcat(paramtemp,params[i]);
247 strcat(paramtemp,"\"");
248 first = 0;
249 }
250 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] got \"%s\" \"%s\" [%s] \"%s\"",conn_get_socket(conn),((prefix)?(prefix):("")),command,paramtemp,((text)?(text):("")));
251 }
252
253 if (conn_get_state(conn)==conn_state_connected) {
254 t_timer_data temp;
255
256 conn_set_state(conn,conn_state_bot_username);
257 temp.n = prefs_get_irc_latency();
258 conn_test_latency(conn,time(NULL),temp);
259 }
260
261 if (handle_irc_con_command(conn, command, numparams, params, text)!=-1) {}
262 else if (conn_get_state(conn)!=conn_state_loggedin) {
263 char temp[MAX_IRC_MESSAGE_LEN+1];
264
265 if ((38+strlen(command)+16+1)<sizeof(temp)) {
266 sprintf(temp,":Unrecognized command \"%s\" (before login)",command);
267 irc_send(conn,ERR_UNKNOWNCOMMAND,temp);
268 } else {
269 irc_send(conn,ERR_UNKNOWNCOMMAND,":Unrecognized command (before login)");
270 }
271 } else {
272 /* command is handled later */
273 unrecognized_before = 1;
274 }
275 /* --- The following should only be executable after login --- */
276 if ((conn_get_state(conn)==conn_state_loggedin)&&(unrecognized_before)) {
277
278 if (handle_irc_log_command(conn, command, numparams, params, text)!=-1) {}
279 else if ((strstart(command,"LAG")!=0)&&(strstart(command,"JOIN")!=0)){
280 linelen = strlen (ircline);
281 bnet_command = xmalloc(linelen + 2);
282 bnet_command[0]='/';
283 strcpy(bnet_command + 1, ircline);
284 handle_command(conn,bnet_command);
285 xfree((void*)bnet_command);
286 }
287 } /* loggedin */
288 if (params)
289 irc_unget_paramelems(params);
290 xfree(line);
291 return 0;
292 }
293
294 extern int handle_irc_packet(t_connection * conn, t_packet const * const packet)
295 {
296 unsigned int i;
297 char ircline[MAX_IRC_MESSAGE_LEN];
298 int ircpos;
299 char const * data;
300
301 if (!packet) {
302 eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
303 return -1;
304 }
305 if (conn_get_class(conn) != conn_class_irc ) {
306 eventlog(eventlog_level_error,__FUNCTION__,"FIXME: handle_irc_packet without any reason (conn->class != conn_class_irc)");
307 return -1;
308 }
309
310 /* eventlog(eventlog_level_debug,__FUNCTION__,"got \"%s\"",packet_get_raw_data_const(packet,0)); */
311
312 memset(ircline,0,sizeof(ircline));
313 data = conn_get_ircline(conn); /* fetch current status */
314 if (data)
315 strcpy(ircline,data);
316 ircpos = strlen(ircline);
317 data = packet_get_raw_data_const(packet,0);
318 for (i=0; i < packet_get_size(packet); i++) {
319 if ((data[i] == '\r')||(data[i] == '\0')) {
320 /* kindly ignore \r and NUL ... */
321 } else if (data[i] == '\n') {
322 /* end of line */
323 handle_irc_line(conn,ircline);
324 memset(ircline,0,sizeof(ircline));
325 ircpos = 0;
326 } else {
327 if (ircpos < MAX_IRC_MESSAGE_LEN-1)
328 ircline[ircpos++] = data[i];
329 else {
330 ircpos++; /* for the statistic :) */
331 eventlog(eventlog_level_warn,__FUNCTION__,"[%d] client exceeded maximum allowed message length by %d characters",conn_get_socket(conn),ircpos-MAX_IRC_MESSAGE_LEN);
332 if ((ircpos-MAX_IRC_MESSAGE_LEN)>100) {
333 /* automatic flood protection */
334 eventlog(eventlog_level_error,__FUNCTION__,"[%d] excess flood",conn_get_socket(conn));
335 return -1;
336 }
337 }
338 }
339 }
340 conn_set_ircline(conn,ircline); /* write back current status */
341 return 0;
342 }
343
344 static int _handle_nick_command(t_connection * conn, int numparams, char ** params, char * text)
345 {
346 /* FIXME: more strict param checking */
347
348 if ((conn_get_loggeduser(conn))&&
349 (conn_get_state(conn)!=conn_state_bot_password &&
350 conn_get_state(conn)!=conn_state_bot_username))
351 {
352 irc_send(conn,ERR_RESTRICTED,":You can't change your nick after login");
353 }
354 else
355 {
356 if ((params)&&(params[0]))
357 {
358 if (conn_get_loggeduser(conn))
359 irc_send_cmd2(conn,conn_get_loggeduser(conn),"NICK","",params[0]);
360 conn_set_loggeduser(conn,params[0]);
361 }
362 else if (text)
363 {
364 if (conn_get_loggeduser(conn))
365 irc_send_cmd2(conn,conn_get_loggeduser(conn),"NICK","",text);
366 conn_set_loggeduser(conn,text);
367 }
368 else
369 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to NICK");
370 if ((conn_get_user(conn))&&(conn_get_loggeduser(conn)))
371 irc_welcome(conn); /* only send the welcome if we have USER and NICK */
372 }
373 return 0;
374 }
375
376 static int _handle_user_command(t_connection * conn, int numparams, char ** params, char * text)
377 {
378 /* RFC 2812 says: */
379 /* <user> <mode> <unused> :<realname>*/
380 /* ircII and X-Chat say: */
381 /* mz SHODAN localhost :Marco Ziech */
382 /* BitchX says: */
383 /* mz +iws mz :Marco Ziech */
384 /* What does this tell us? Ditch mode and unused, they don't contain what they should. */
385 char * user = NULL;
386 char * mode = NULL;
387 char * unused = NULL;
388 char * realname = NULL;
389
390 if ((numparams>=3)&&(params[0])&&(params[1])&&(params[2])&&(text))
391 {
392 user = params[0];
393 mode = params[1];
394 unused = params[2];
395 realname = text;
396 if (conn_get_user(conn))
397 {
398 irc_send(conn,ERR_ALREADYREGISTRED,":You are already registred");
399 }
400 else
401 {
402 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] got USER: user=\"%s\" mode=\"%s\" unused=\"%s\" realname=\"%s\"",conn_get_socket(conn),user,mode,unused,realname);
403 conn_set_user(conn,user);
404 conn_set_owner(conn,realname);
405 if (conn_get_loggeduser(conn))
406 irc_welcome(conn); /* only send the welcome if we have USER and NICK */
407 }
408 }
409 else
410 {
411 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to USER");
412 }
413 return 0;
414 }
415
416 static int _handle_ping_command(t_connection * conn, int numparams, char ** params, char * text)
417 {
418 /* Dizzy: just ignore this because RFC says we should not reply client PINGs
419 * NOTE: RFC2812 doesn't seem to be very expressive about this ... */
420 if (numparams)
421 irc_send_pong(conn,params[0]);
422 else
423 irc_send_pong(conn,text);
424 return 0;
425 }
426
427 static int _handle_pong_command(t_connection * conn, int numparams, char ** params, char * text)
428 {
429
430 /* NOTE: RFC2812 doesn't seem to be very expressive about this ... */
431 if (conn_get_ircping(conn)==0)
432 {
433 eventlog(eventlog_level_warn,__FUNCTION__,"[%d] PONG without PING",conn_get_socket(conn));
434 }
435 else
436 {
437 unsigned int val = 0;
438 char * sname;
439
440 if (numparams>=1)
441 {
442 val = atoi(params[0]);
443 sname = params[0];
444 }
445 else if (text)
446 {
447 val = atoi(text);
448 sname = text;
449 }
450 else
451 {
452 val = 0;
453 sname = 0;
454 }
455
456 if (conn_get_ircping(conn) != val)
457 {
458 if ((!(sname)) || (strcmp(sname,server_get_name())!=0))
459 {
460 /* Actually the servername should not be always accepted but we aren't that pedantic :) */
461 eventlog(eventlog_level_warn,__FUNCTION__,"[%d] got bad PONG (%u!=%u && %s!=%s)",conn_get_socket(conn),val,conn_get_ircping(conn),sname,server_get_name());
462 return -1;
463 }
464 }
465 conn_set_latency(conn,get_ticks()-conn_get_ircping(conn));
466 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] latency is now %d (%u-%u)",conn_get_socket(conn),get_ticks()-conn_get_ircping(conn),get_ticks(),conn_get_ircping(conn));
467 conn_set_ircping(conn,0);
468 }
469 return 0;
470 }
471
472 static int _handle_pass_command(t_connection * conn, int numparams, char ** params, char * text)
473 {
474 if ((!conn_get_ircpass(conn))&&(conn_get_state(conn)==conn_state_bot_username))
475 {
476 t_hash h;
477
478 if (numparams>=1)
479 {
480 bnet_hash(&h,strlen(params[0]),params[0]);
481 conn_set_ircpass(conn,hash_get_str(h));
482 }
483 else
484 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to PASS");
485 }
486 else
487 {
488 eventlog(eventlog_level_warn,__FUNCTION__,"[%d] client tried to set password twice with PASS",conn_get_socket(conn));
489 }
490 return 0;
491 }
492
493 static int _handle_privmsg_command(t_connection * conn, int numparams, char ** params, char * text)
494 {
495 if ((numparams>=1)&&(text))
496 {
497 int i;
498 char ** e;
499
500 e = irc_get_listelems(params[0]);
501 /* FIXME: support wildcards! */
502
503 //start amadeo: code was sent by some unkown fellow of pvpgn(maybe u wanna give us your name
504 // for any credits), it adds nick-registration,i changed some things here and there...
505 for (i=0;((e)&&(e[i]));i++)
506 {
507 if (strcasecmp(e[i],"NICKSERV")==0)
508 {
509 char * pass;
510 char * p;
511
512 pass = strchr(text,' ');
513 if (pass)
514 *pass++ = '\0';
515
516 if (strcasecmp(text,"identify")==0)
517 {
518 switch (conn_get_state(conn))
519 {
520 case conn_state_bot_password:
521 {
522 if (pass)
523 {
524 t_hash h;
525
526 for (p = pass; *p; p++)
527 if (isupper((int)*p)) *p = tolower(*p);
528 bnet_hash(&h,strlen(pass),pass);
529 irc_authenticate(conn,hash_get_str(h));
530 }
531 else
532 {
533 irc_send_cmd(conn,"NOTICE",":Syntax: IDENTIFY password(max 16 characters)");
534 }
535 break;
536 }
537 case conn_state_loggedin:
538 {
539 irc_send_cmd(conn,"NOTICE",":You don't need to IDENTIFY");
540 break;
541 }
542 default: ;
543 eventlog(eventlog_level_trace,__FUNCTION__,"got /msg in unexpected connection state (%s)",conn_state_get_str(conn_get_state(conn)));
544 }
545 }
546 else if (strcasecmp(text,"register")==0)
547 {
548 unsigned int j;
549 t_hash passhash;
550 t_account * temp;
551 char msgtemp[MAX_MESSAGE_LEN];
552 char * username=(char *)conn_get_loggeduser(conn);
553
554 if (account_check_name(username)<0)
555 {
556 message_send_text(conn,message_type_error,conn,"Account name contains invalid symbol!");
557 break;
558 }
559
560 if (!pass || pass[0]=='\0' || (strlen(pass)>16) )
561 {
562 message_send_text(conn,message_type_error,conn,":Syntax: REGISTER password(max 16 characters)");
563 break;
564 }
565
566
567 for (j=0; j<strlen(pass); j++)
568 if (isupper((int)pass[j])) pass[j] = tolower((int)pass[j]);
569
570 bnet_hash(&passhash,strlen(pass),pass);
571
572 sprintf(msgtemp,"Trying to create account \"%s\" with password \"%s\"",username,pass);
573 message_send_text(conn,message_type_info,conn,msgtemp);
574
575 temp = accountlist_create_account(username,hash_get_str(passhash));
576 if (!temp) {
577 message_send_text(conn,message_type_error,conn,"Failed to create account!");
578 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] account \"%s\" not created (failed)",conn_get_socket(conn),username);
579 conn_unget_chatname(conn,username);
580 break;
581 }
582
583 sprintf(msgtemp,"Account "UID_FORMAT" created.",account_get_uid(temp));
584 message_send_text(conn,message_type_info,conn,msgtemp);
585 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] account \"%s\" created",conn_get_socket(conn),username);
586 conn_unget_chatname(conn,username);
587 }
588 else
589 {
590 char tmp[MAX_IRC_MESSAGE_LEN+1];
591
592 irc_send_cmd(conn,"NOTICE",":Invalid arguments for NICKSERV");
593 sprintf(tmp,":Unrecognized command \"%s\"",text);
594 irc_send_cmd(conn,"NOTICE",tmp);
595 }
596 }
597
598 else if (conn_get_state(conn)==conn_state_loggedin)
599 {
600 if (e[i][0]=='#')
601 {
602 /* channel message */
603 t_channel * channel;
604
605 if ((channel = channellist_find_channel_by_name(irc_convert_ircname(e[i]),NULL,NULL)))
606 {
607 if ((strlen(text)>=9)&&(strncmp(text,"\001ACTION ",8)==0)&&(text[strlen(text)-1]=='\001'))
608 { /* at least "\001ACTION \001" */
609 /* it's a CTCP ACTION message */
610 text = text + 8;
611 text[strlen(text)-1] = '\0';
612 channel_message_send(channel,message_type_emote,conn,text);
613 }
614 else
615 channel_message_send(channel,message_type_talk,conn,text);
616 }
617 else
618 {
619 irc_send(conn,ERR_NOSUCHCHANNEL,":No such channel");
620 }
621 }
622 else
623 {
624 /* whisper */
625 t_connection * user;
626
627 if ((user = connlist_find_connection_by_accountname(e[i])))
628 {
629 message_send_text(user,message_type_whisper,conn,text);
630 }
631 else
632 {
633 irc_send(conn,ERR_NOSUCHNICK,":No such user");
634 }
635 }
636 }
637 }
638 if (e)
639 irc_unget_listelems(e);
640 }
641 else
642 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to PRIVMSG");
643 return 0;
644 }
645
646 static int _handle_notice_command(t_connection * conn, int numparams, char ** params, char * text)
647 {
648 if ((numparams>=1)&&(text))
649 {
650 int i;
651 char ** e;
652
653 e = irc_get_listelems(params[0]);
654 /* FIXME: support wildcards! */
655
656 for (i=0;((e)&&(e[i]));i++)
657 {
658 if (conn_get_state(conn)==conn_state_loggedin)
659 {
660 t_connection * user;
661
662 if ((user = connlist_find_connection_by_accountname(e[i])))
663 {
664 irc_send_cmd2(user,conn_get_loggeduser(conn),"NOTICE",conn_get_loggeduser(user),text);
665 }
666 else
667 {
668 irc_send(conn,ERR_NOSUCHNICK,":No such user");
669 }
670 }
671 }
672 if (e)
673 irc_unget_listelems(e);
674 }
675 else
676 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to PRIVMSG");
677 return 0;
678 }
679
680 static int _handle_who_command(t_connection * conn, int numparams, char ** params, char * text)
681 {
682 if (numparams>=1)
683 {
684 int i;
685 char ** e;
686
687 e = irc_get_listelems(params[0]);
688 for (i=0; ((e)&&(e[i]));i++)
689 {
690 irc_who(conn,e[i]);
691 }
692 irc_send(conn,RPL_ENDOFWHO,":End of WHO list"); /* RFC2812 only requires this to be sent if a list of names was given. Undernet seems to always send it, so do we :) */
693 if (e)
694 irc_unget_listelems(e);
695 }
696 else
697 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to WHO");
698 return 0;
699 }
700
701 static int _handle_list_command(t_connection * conn, int numparams, char ** params, char * text)
702 {
703 char temp[MAX_IRC_MESSAGE_LEN];
704
705 irc_send(conn,RPL_LISTSTART,"Channel :Users Name"); /* backward compatibility */
706 if (numparams==0)
707 {
708 t_elem const * curr;
709
710 LIST_TRAVERSE_CONST(channellist(),curr)
711 {
712 t_channel const * channel = elem_get_data(curr);
713 char const * tempname;
714 char const * notopic = "No topic is set";
715 char * topic = channel_get_topic(channel_get_name(channel));
716
717 tempname = irc_convert_channel(channel);
718
719 //FIXME: AARON: only list channels like in /channels command
720
721 if (topic)
722 {
723 if (strlen(tempname)+1+20+1+1+strlen(topic)<MAX_IRC_MESSAGE_LEN)
724 sprintf(temp,"%s %u :%s",tempname,channel_get_length(channel),topic);
725 else
726 eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
727 }
728 else
729 {
730 if (strlen(tempname)+1+20+1+1+strlen(notopic)<MAX_IRC_MESSAGE_LEN)
731 sprintf(temp,"%s %u :%s",tempname,channel_get_length(channel),notopic);
732 else
733 eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
734 }
735 irc_send(conn,RPL_LIST,temp);
736 }
737 }
738 else if (numparams>=1)
739 {
740 int i;
741 char ** e;
742
743 /* FIXME: support wildcards! */
744 e = irc_get_listelems(params[0]);
745 for (i=0;((e)&&(e[i]));i++)
746 {
747 t_channel const * channel;
748 char const * verytemp; /* another good example for creative naming conventions :) */
749 char const * tempname;
750 char const * notopic = "No topic is set";
751 char * topic;
752
753 verytemp = irc_convert_ircname(e[i]);
754 if (!verytemp)
755 continue; /* something is wrong with the name ... */
756 channel = channellist_find_channel_by_name(verytemp,NULL,NULL);
757 if (!channel)
758 continue; /* channel doesn't exist */
759
760 topic = channel_get_topic(channel_get_name(channel));
761 tempname = irc_convert_channel(channel);
762
763 if (topic)
764 {
765 if (strlen(tempname)+1+20+1+1+strlen(topic)<MAX_IRC_MESSAGE_LEN)
766 sprintf(temp,"%s %u :%s",tempname,channel_get_length(channel),topic);
767 else
768 eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
769 }
770 else
771 {
772 if (strlen(tempname)+1+20+1+1+strlen(notopic)<MAX_IRC_MESSAGE_LEN)
773 sprintf(temp,"%s %u :%s",tempname,channel_get_length(channel),notopic);
774 else
775 eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
776 }
777 irc_send(conn,RPL_LIST,temp);
778 }
779 if (e)
780 irc_unget_listelems(e);
781 }
782 irc_send(conn,RPL_LISTEND,":End of LIST command");
783 return 0;
784 }
785
786 static int _handle_topic_command(t_connection * conn, int numparams, char ** params, char * text)
787 {
788 char ** e = NULL;
789
790 if (params!=NULL) e = irc_get_listelems(params[0]);
791
792 if ((e)&&(e[0]))
793 {
794 t_channel *channel = conn_get_channel(conn);
795
796 if (channel)
797 {
798 char * topic;
799 char temp[MAX_IRC_MESSAGE_LEN];
800 char const * ircname = irc_convert_ircname(e[0]);
801
802 if ((ircname) && (strcasecmp(channel_get_name(channel),ircname)==0))
803 {
804 if ((topic = channel_get_topic(channel_get_name(channel))))
805 {
806 sprintf(temp,"%s :%s",ircname,topic);
807 irc_send(conn,RPL_TOPIC,temp);
808 }
809 else
810 irc_send(conn,RPL_NOTOPIC,":No topic is set");
811 }
812 else
813 irc_send(conn,ERR_NOTONCHANNEL,":You are not on that channel");
814 }
815 else
816 {
817 irc_send(conn,ERR_NOTONCHANNEL,":You're not on a channel");
818 }
819 irc_unget_listelems(e);
820 }
821 else
822 irc_send(conn,ERR_NEEDMOREPARAMS,":too few arguments to TOPIC");
823 return 0;
824 }
825
826 static int _handle_join_command(t_connection * conn, int numparams, char ** params, char * text)
827 {
828 if (numparams>=1)
829 {
830 char ** e;
831
832 e = irc_get_listelems(params[0]);
833 if ((e)&&(e[0]))
834 {
835 char const * ircname = irc_convert_ircname(e[0]);
836 char * old_channel_name = NULL;
837 t_channel * old_channel = conn_get_channel(conn);
838
839 if (old_channel)
840 old_channel_name = xstrdup(irc_convert_channel(old_channel));
841
842 if ((!(ircname)) || (conn_set_channel(conn,ircname)<0))
843 {
844 irc_send(conn,ERR_NOSUCHCHANNEL,":JOIN failed"); /* FIXME: be more precise; what is the real error code for that? */
845 }
846 else
847 {
848 t_channel * channel;
849
850
851
852 channel = conn_get_channel(conn);
853 if (channel!=old_channel)
854 {
855 char temp[MAX_IRC_MESSAGE_LEN];
856 char * topic;
857
858 channel_set_userflags(conn);
859 message_send_text(conn,message_type_join,conn,NULL); /* we have to send the JOIN acknowledgement */
860 ircname=irc_convert_channel(channel);
861
862 if ((topic = channel_get_topic(channel_get_name(channel))))
863 {
864
865 if ((strlen(ircname)+1+1+strlen(topic)+1)<MAX_IRC_MESSAGE_LEN)
866 {
867 sprintf(temp,"%s :%s",ircname,topic);
868 irc_send(conn,RPL_TOPIC,temp);
869 }
870
871 if ((strlen(ircname)+1+strlen("FIXME 0")+1)<MAX_IRC_MESSAGE_LEN)
872 {
873 sprintf(temp,"%s FIXME 0",ircname);
874 irc_send(conn,RPL_TOPICWHOTIME,temp); /* FIXME: this in an undernet extension but other servers support it too */
875 }
876 }
877 else
878 irc_send(conn,RPL_NOTOPIC,":No topic is set");
879
880 irc_send_rpl_namreply(conn,channel);
881 irc_send(conn,RPL_ENDOFNAMES,":End of NAMES list");
882
883 if (old_channel_name)
884 {
885 irc_send_cmd2(conn,conn_get_loggeduser(conn),"PART",old_channel_name,"only one channel at once");
886 }
887 }
888 }
889 if (old_channel_name) xfree((void *)old_channel_name);
890 }
891 if (e)
892 irc_unget_listelems(e);
893 }
894 else
895 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to JOIN");
896 return 0;
897 }
898
899 static int _handle_names_command(t_connection * conn, int numparams, char ** params, char * text)
900 {
901 t_channel * channel;
902
903 if (numparams>=1)
904 {
905 char ** e;
906 char const * ircname;
907 char const * verytemp;
908 char temp[MAX_IRC_MESSAGE_LEN];
909 int i;
910
911 e = irc_get_listelems(params[0]);
912 for (i=0;((e)&&(e[i]));i++)
913 {
914 verytemp = irc_convert_ircname(e[i]);
915
916 if (!verytemp)
917 continue; /* something is wrong with the name ... */
918 channel = channellist_find_channel_by_name(verytemp,NULL,NULL);
919 if (!channel)
920 continue; /* channel doesn't exist */
921 irc_send_rpl_namreply(conn,channel);
922 ircname=irc_convert_channel(channel);
923 if ((strlen(ircname)+1+strlen(":End of NAMES list")+1)<MAX_IRC_MESSAGE_LEN)
924 {
925 sprintf(temp,"%s :End of NAMES list",ircname);
926 irc_send(conn,RPL_ENDOFNAMES,temp);
927 }
928 else
929 irc_send(conn,RPL_ENDOFNAMES,":End of NAMES list");
930 }
931 if (e)
932 irc_unget_listelems(e);
933 }
934 else if (numparams==0)
935 {
936 t_elem const * curr;
937 LIST_TRAVERSE_CONST(channellist(),curr)
938 {
939 channel = elem_get_data(curr);
940 irc_send_rpl_namreply(conn,channel);
941 }
942 irc_send(conn,RPL_ENDOFNAMES,"* :End of NAMES list");
943 }
944 return 0;
945 }
946
947 static int _handle_mode_command(t_connection * conn, int numparams, char ** params, char * text)
948 {
949 /* FIXME: Not yet implemented */
950 return 0;
951 }
952
953 static int _handle_userhost_command(t_connection * conn, int numparams, char ** params, char * text)
954 {
955 /* FIXME: Send RPL_USERHOST */
956 return 0;
957 }
958
959 static int _handle_quit_command(t_connection * conn, int numparams, char ** params, char * text)
960 {
961 conn_set_channel(conn, NULL);
962 conn_set_state(conn, conn_state_destroy);
963 return 0;
964 }
965
966 static int _handle_ison_command(t_connection * conn, int numparams, char ** params, char * text)
967 {
968 char temp[MAX_IRC_MESSAGE_LEN];
969 char first = 1;
970
971 if (numparams>=1)
972 {
973 int i;
974
975 temp[0]='\0';
976 for (i=0; (i<numparams && (params) && (params[i]));i++)
977 {
978 if (connlist_find_connection_by_accountname(params[i]))
979 {
980 if (first)
981 strcat(temp,":");
982 else
983 strcat(temp," ");
984 strcat(temp,params[i]);
985 first = 0;
986 }
987 }
988 irc_send(conn,RPL_ISON,temp);
989 }
990 else
991 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to ISON");
992 return 0;
993 }
994
995 static int _handle_whois_command(t_connection * conn, int numparams, char ** params, char * text)
996 {
997 char temp[MAX_IRC_MESSAGE_LEN];
998 char temp2[MAX_IRC_MESSAGE_LEN];
999 if (numparams>=1)
1000 {
1001 int i;
1002 char ** e;
1003 t_connection * c;
1004 t_channel * chan;
1005
1006 temp[0]='\0';
1007 temp2[0]='\0';
1008 e = irc_get_listelems(params[0]);
1009 for (i=0; ((e)&&(e[i]));i++)
1010 {
1011 if ((c = connlist_find_connection_by_accountname(e[i])))
1012 {
1013 if (prefs_get_hide_addr() && !(account_get_command_groups(conn_get_account(conn)) & command_get_group("/admin-addr")))
1014 sprintf(temp,"%s %s hidden * :%s",e[i],clienttag_uint_to_str(conn_get_clienttag(c)),"PvPGN user");
1015 else
1016 sprintf(temp,"%s %s %s * :%s",e[i],clienttag_uint_to_str(conn_get_clienttag(c)),addr_num_to_ip_str(conn_get_addr(c)),"PvPGN user");
1017 irc_send(conn,RPL_WHOISUSER,temp);
1018
1019 if ((chan=conn_get_channel(conn)))
1020 {
1021 char flg;
1022 unsigned int flags;
1023
1024 flags = conn_get_flags(c);
1025
1026 if (flags & MF_BLIZZARD)
1027 flg='@';
1028 else if ((flags & MF_BNET) || (flags & MF_GAVEL))
1029 flg='%';
1030 else if (flags & MF_VOICE)
1031 flg='+';
1032 else flg = ' ';
1033 sprintf(temp2,"%s :%c%s",e[i],flg,irc_convert_channel(chan));
1034 irc_send(conn,RPL_WHOISCHANNELS,temp2);
1035 }
1036
1037 }
1038 else
1039 irc_send(conn,ERR_NOSUCHNICK,":No such nick/channel");
1040
1041 }
1042 irc_send(conn,RPL_ENDOFWHOIS,":End of /WHOIS list");
1043 if (e)
1044 irc_unget_listelems(e);
1045 }
1046 else
1047 irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to WHOIS");
1048 return 0;
1049 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1