2 38b9cb88 2001-12-14 alex * ngIRCd -- The Next Generation IRC Daemon
3 bdaf53e7 2004-02-28 alex * Copyright (c)2001-2004 Alexander Barton <alex@barton.de>
5 490f28ff 2002-12-12 alex * This program is free software; you can redistribute it and/or modify
6 490f28ff 2002-12-12 alex * it under the terms of the GNU General Public License as published by
7 490f28ff 2002-12-12 alex * the Free Software Foundation; either version 2 of the License, or
8 490f28ff 2002-12-12 alex * (at your option) any later version.
9 490f28ff 2002-12-12 alex * Please read the file COPYING, README and AUTHORS for more information.
11 490f28ff 2002-12-12 alex * IRC commands
15 ca33cbda 2002-03-12 alex #include "portab.h"
17 129a22a2 2005-04-18 alex static char UNUSED id[] = "$Id: irc.c,v 1.126 2005/04/18 15:44:39 alex Exp $";
19 ca33cbda 2002-03-12 alex #include "imp.h"
20 38b9cb88 2001-12-14 alex #include <assert.h>
21 44a2b3cf 2002-12-12 alex #include <stdio.h>
22 2a13cd22 2001-12-23 alex #include <string.h>
24 42c4e6c7 2003-01-13 alex #include "ngircd.h"
25 42c4e6c7 2003-01-13 alex #include "conn.h"
26 42c4e6c7 2003-01-13 alex #include "resolve.h"
27 42c4e6c7 2003-01-13 alex #include "conf.h"
28 b8d7dcec 2002-12-30 alex #include "conn-func.h"
29 2a13cd22 2001-12-23 alex #include "client.h"
30 c2f60abe 2002-05-27 alex #include "channel.h"
31 0c471b84 2002-11-30 alex #include "defines.h"
32 ef7f7a90 2002-02-27 alex #include "irc-write.h"
33 2a13cd22 2001-12-23 alex #include "log.h"
34 2a13cd22 2001-12-23 alex #include "messages.h"
35 c2f60abe 2002-05-27 alex #include "parse.h"
37 ca33cbda 2002-03-12 alex #include "exp.h"
38 38b9cb88 2001-12-14 alex #include "irc.h"
41 8adff592 2005-03-19 fw LOCAL char *Option_String PARAMS(( CONN_ID Idx ));
45 0c471b84 2002-11-30 alex IRC_ERROR( CLIENT *Client, REQUEST *Req )
47 bbfe9e8b 2001-12-25 alex assert( Client != NULL );
48 bbfe9e8b 2001-12-25 alex assert( Req != NULL );
50 0c471b84 2002-11-30 alex if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
51 0c471b84 2002-11-30 alex else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
53 0c471b84 2002-11-30 alex return CONNECTED;
54 0c471b84 2002-11-30 alex } /* IRC_ERROR */
58 129a22a2 2005-04-18 alex * Kill client on request.
59 129a22a2 2005-04-18 alex * This function implements the IRC command "KILL" wich is used to selectively
60 129a22a2 2005-04-18 alex * disconnect clients. It can be used by IRC operators and servers, for example
61 129a22a2 2005-04-18 alex * to "solve" nick collisions after netsplits.
62 129a22a2 2005-04-18 alex * Please note that this function is also called internally, without a real
63 129a22a2 2005-04-18 alex * KILL command beeing received over the network! Client is Client_ThisServer()
64 129a22a2 2005-04-18 alex * in this case. */
66 0c471b84 2002-11-30 alex IRC_KILL( CLIENT *Client, REQUEST *Req )
68 0c471b84 2002-11-30 alex CLIENT *prefix, *c;
69 129a22a2 2005-04-18 alex char reason[COMMAND_LEN], *msg;
70 01b58a05 2002-12-31 alex CONN_ID my_conn, conn;
72 72ebf4f2 2001-12-27 alex assert( Client != NULL );
73 72ebf4f2 2001-12-27 alex assert( Req != NULL );
75 129a22a2 2005-04-18 alex if(( Client_Type( Client ) != CLIENT_SERVER ) &&
76 129a22a2 2005-04-18 alex ( ! Client_OperByMe( Client )))
78 129a22a2 2005-04-18 alex /* The originator of the KILL is neither an IRC operator of
79 129a22a2 2005-04-18 alex * this server nor a server. */
80 129a22a2 2005-04-18 alex return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG,
81 129a22a2 2005-04-18 alex Client_ID( Client ));
84 129a22a2 2005-04-18 alex if( Req->argc != 2 )
86 129a22a2 2005-04-18 alex /* This command requires exactly 2 parameters! */
87 129a22a2 2005-04-18 alex return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
88 129a22a2 2005-04-18 alex Client_ID( Client ), Req->command );
91 b99af4fa 2002-12-06 alex if( Req->prefix ) prefix = Client_Search( Req->prefix );
92 b99af4fa 2002-12-06 alex else prefix = Client;
93 0c471b84 2002-11-30 alex if( ! prefix )
95 129a22a2 2005-04-18 alex Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!",
96 129a22a2 2005-04-18 alex Req->prefix );
97 0c471b84 2002-11-30 alex prefix = Client_ThisServer( );
100 129a22a2 2005-04-18 alex if( Client != Client_ThisServer( ))
102 129a22a2 2005-04-18 alex /* This is a "real" KILL received from the network. */
103 129a22a2 2005-04-18 alex Log( LOG_NOTICE|LOG_snotice, "Got KILL command from \"%s\" for \"%s\": %s",
104 129a22a2 2005-04-18 alex Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
107 4d2f279d 2002-12-26 alex /* Build reason string */
108 129a22a2 2005-04-18 alex if( Client_Type( Client ) == CLIENT_USER )
110 129a22a2 2005-04-18 alex /* Prefix the "reason" if the originator is a regular user,
111 129a22a2 2005-04-18 alex * so users can't spoof KILLs of servers. */
112 129a22a2 2005-04-18 alex snprintf( reason, sizeof( reason ), "KILLed by %s: %s",
113 129a22a2 2005-04-18 alex Client_ID( Client ), Req->argv[1] );
116 129a22a2 2005-04-18 alex strlcpy( reason, Req->argv[1], sizeof( reason ));
118 4d2f279d 2002-12-26 alex /* Inform other servers */
119 129a22a2 2005-04-18 alex IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s",
120 129a22a2 2005-04-18 alex Req->argv[0], reason );
122 01b58a05 2002-12-31 alex /* Save ID of this connection */
123 01b58a05 2002-12-31 alex my_conn = Client_Conn( Client );
125 4d2f279d 2002-12-26 alex /* Do we host such a client? */
126 0c471b84 2002-11-30 alex c = Client_Search( Req->argv[0] );
129 129a22a2 2005-04-18 alex if(( Client_Type( c ) != CLIENT_USER ) &&
130 129a22a2 2005-04-18 alex ( Client_Type( c ) != CLIENT_GOTNICK ))
132 129a22a2 2005-04-18 alex /* Target of this KILL is not a regular user, this is
133 129a22a2 2005-04-18 alex * invalid! So we ignore this case if we received a
134 129a22a2 2005-04-18 alex * regular KILL from the network and try to kill the
135 129a22a2 2005-04-18 alex * client/connection anyway (but log an error!) if the
136 129a22a2 2005-04-18 alex * origin is the local server. */
138 129a22a2 2005-04-18 alex if( Client != Client_ThisServer( ))
140 129a22a2 2005-04-18 alex /* Invalid KILL received from remote */
141 129a22a2 2005-04-18 alex if( Client_Type( c ) == CLIENT_SERVER )
142 129a22a2 2005-04-18 alex msg = ERR_CANTKILLSERVER_MSG;
144 129a22a2 2005-04-18 alex msg = ERR_NOPRIVILEGES_MSG;
145 129a22a2 2005-04-18 alex return IRC_WriteStrClient( Client, msg,
146 129a22a2 2005-04-18 alex Client_ID( Client ));
149 129a22a2 2005-04-18 alex Log( LOG_ERR, "Got KILL for invalid client type: %d, \"%s\"!",
150 129a22a2 2005-04-18 alex Client_Type( c ), Req->argv[0] );
153 129a22a2 2005-04-18 alex /* Kill client NOW! */
154 129a22a2 2005-04-18 alex conn = Client_Conn( Client_NextHop( c ));
155 129a22a2 2005-04-18 alex Client_Destroy( c, NULL, reason, false );
156 129a22a2 2005-04-18 alex if( conn > NONE )
157 129a22a2 2005-04-18 alex Conn_Close( conn, NULL, reason, true );
160 129a22a2 2005-04-18 alex Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] );
162 4d2f279d 2002-12-26 alex /* Are we still connected or were we killed, too? */
163 129a22a2 2005-04-18 alex if(( my_conn > NONE ) && ( Client_GetFromConn( my_conn )))
164 129a22a2 2005-04-18 alex return CONNECTED;
166 129a22a2 2005-04-18 alex return DISCONNECTED;
167 0c471b84 2002-11-30 alex } /* IRC_KILL */
171 c2f60abe 2002-05-27 alex IRC_NOTICE( CLIENT *Client, REQUEST *Req )
173 db58d347 2002-01-05 alex CLIENT *to, *from;
175 72ebf4f2 2001-12-27 alex assert( Client != NULL );
176 72ebf4f2 2001-12-27 alex assert( Req != NULL );
178 1e83e666 2002-10-09 alex if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return CONNECTED;
180 72ebf4f2 2001-12-27 alex /* Falsche Anzahl Parameter? */
181 72ebf4f2 2001-12-27 alex if( Req->argc != 2 ) return CONNECTED;
183 c7408364 2002-03-25 alex if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
184 db58d347 2002-01-05 alex else from = Client;
185 c2ee5437 2002-01-11 alex if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
187 72ebf4f2 2001-12-27 alex to = Client_Search( Req->argv[0] );
188 9fd8254a 2002-06-11 alex if(( to ) && ( Client_Type( to ) == CLIENT_USER ))
190 72ebf4f2 2001-12-27 alex /* Okay, Ziel ist ein User */
191 db58d347 2002-01-05 alex return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
193 db58d347 2002-01-05 alex else return CONNECTED;
194 72ebf4f2 2001-12-27 alex } /* IRC_NOTICE */
198 0c471b84 2002-11-30 alex IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
200 0c471b84 2002-11-30 alex CLIENT *cl, *from;
201 180095be 2002-02-27 alex CHANNEL *chan;
203 fb9d6ce1 2001-12-31 alex assert( Client != NULL );
204 fb9d6ce1 2001-12-31 alex assert( Req != NULL );
206 fb9d6ce1 2001-12-31 alex /* Falsche Anzahl Parameter? */
207 0c471b84 2002-11-30 alex if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
208 0c471b84 2002-11-30 alex if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
209 180095be 2002-02-27 alex if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
211 c7408364 2002-03-25 alex if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
212 180095be 2002-02-27 alex else from = Client;
213 0c471b84 2002-11-30 alex if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
215 0c471b84 2002-11-30 alex cl = Client_Search( Req->argv[0] );
218 0c471b84 2002-11-30 alex /* Okay, Ziel ist ein Client. Aber ist es auch ein User? */
219 0c471b84 2002-11-30 alex if( Client_Type( cl ) != CLIENT_USER ) return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
221 0c471b84 2002-11-30 alex /* Okay, Ziel ist ein User */
222 0c471b84 2002-11-30 alex if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
224 0c471b84 2002-11-30 alex /* Ziel-User ist AWAY: Meldung verschicken */
225 0c471b84 2002-11-30 alex if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
228 0c471b84 2002-11-30 alex /* Text senden */
229 0c471b84 2002-11-30 alex if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
230 0c471b84 2002-11-30 alex return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
233 0c471b84 2002-11-30 alex chan = Channel_Search( Req->argv[0] );
234 0c471b84 2002-11-30 alex if( chan ) return Channel_Write( chan, from, Client, Req->argv[1] );
236 0c471b84 2002-11-30 alex return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
237 0c471b84 2002-11-30 alex } /* IRC_PRIVMSG */
241 42c4e6c7 2003-01-13 alex IRC_TRACE( CLIENT *Client, REQUEST *Req )
243 ac4f25e3 2003-03-19 alex CLIENT *from, *target, *c;
244 42c4e6c7 2003-01-13 alex CONN_ID idx, idx2;
245 8adff592 2005-03-19 fw char user[CLIENT_USER_LEN];
247 42c4e6c7 2003-01-13 alex assert( Client != NULL );
248 42c4e6c7 2003-01-13 alex assert( Req != NULL );
250 42c4e6c7 2003-01-13 alex /* Bad number of arguments? */
251 42c4e6c7 2003-01-13 alex if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
253 42c4e6c7 2003-01-13 alex /* Search sender */
254 42c4e6c7 2003-01-13 alex if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
255 42c4e6c7 2003-01-13 alex else from = Client;
256 42c4e6c7 2003-01-13 alex if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
258 42c4e6c7 2003-01-13 alex /* Search target */
259 42c4e6c7 2003-01-13 alex if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
260 42c4e6c7 2003-01-13 alex else target = Client_ThisServer( );
262 42c4e6c7 2003-01-13 alex /* Forward command to other server? */
263 42c4e6c7 2003-01-13 alex if( target != Client_ThisServer( ))
265 42c4e6c7 2003-01-13 alex if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
267 42c4e6c7 2003-01-13 alex /* Send RPL_TRACELINK back to initiator */
268 42c4e6c7 2003-01-13 alex idx = Client_Conn( Client ); assert( idx > NONE );
269 42c4e6c7 2003-01-13 alex idx2 = Client_Conn( Client_NextHop( target )); assert( idx2 > NONE );
270 62796722 2003-03-31 alex if( ! IRC_WriteStrClient( from, RPL_TRACELINK_MSG, Client_ID( from ), PACKAGE_NAME, PACKAGE_VERSION, Client_ID( target ), Client_ID( Client_NextHop( target )), Option_String( idx2 ), time( NULL ) - Conn_StartTime( idx2 ), Conn_SendQ( idx ), Conn_SendQ( idx2 ))) return DISCONNECTED;
272 42c4e6c7 2003-01-13 alex /* Forward command */
273 42c4e6c7 2003-01-13 alex IRC_WriteStrClientPrefix( target, from, "TRACE %s", Req->argv[0] );
274 42c4e6c7 2003-01-13 alex return CONNECTED;
277 ac4f25e3 2003-03-19 alex /* Infos about all connected servers */
278 ac4f25e3 2003-03-19 alex c = Client_First( );
281 ac4f25e3 2003-03-19 alex if( Client_Conn( c ) > NONE )
283 ac4f25e3 2003-03-19 alex /* Local client */
284 ac4f25e3 2003-03-19 alex if( Client_Type( c ) == CLIENT_SERVER )
286 ac4f25e3 2003-03-19 alex /* Server link */
287 bdaf53e7 2004-02-28 alex strlcpy( user, Client_User( c ), sizeof( user ));
288 bdaf53e7 2004-02-28 alex if( user[0] == '~' ) strlcpy( user, "unknown", sizeof( user ));
289 bdaf53e7 2004-02-28 alex if( ! IRC_WriteStrClient( from, RPL_TRACESERVER_MSG, Client_ID( from ), Client_ID( c ), user, Client_Hostname( c ), Client_Mask( Client_ThisServer( )), Option_String( Client_Conn( c )))) return DISCONNECTED;
291 ac4f25e3 2003-03-19 alex if(( Client_Type( c ) == CLIENT_USER ) && ( strchr( Client_Modes( c ), 'o' )))
293 ac4f25e3 2003-03-19 alex /* IRC Operator */
294 ac4f25e3 2003-03-19 alex if( ! IRC_WriteStrClient( from, RPL_TRACEOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
297 ac4f25e3 2003-03-19 alex c = Client_Next( c );
300 7b6e2662 2003-11-05 alex IRC_SetPenalty( Client, 3 );
301 62796722 2003-03-31 alex return IRC_WriteStrClient( from, RPL_TRACEEND_MSG, Client_ID( from ), Conf_ServerName, PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel );
302 42c4e6c7 2003-01-13 alex } /* IRC_TRACE */
306 2152e377 2003-01-15 alex IRC_HELP( CLIENT *Client, REQUEST *Req )
308 2152e377 2003-01-15 alex COMMAND *cmd;
310 2152e377 2003-01-15 alex assert( Client != NULL );
311 2152e377 2003-01-15 alex assert( Req != NULL );
313 2152e377 2003-01-15 alex /* Bad number of arguments? */
314 2152e377 2003-01-15 alex if( Req->argc > 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
316 2152e377 2003-01-15 alex cmd = Parse_GetCommandStruct( );
317 2152e377 2003-01-15 alex while( cmd->name )
319 2152e377 2003-01-15 alex if( ! IRC_WriteStrClient( Client, "NOTICE %s :%s", Client_ID( Client ), cmd->name )) return DISCONNECTED;
323 7b6e2662 2003-11-05 alex IRC_SetPenalty( Client, 2 );
324 2152e377 2003-01-15 alex return CONNECTED;
325 2152e377 2003-01-15 alex } /* IRC_HELP */
329 ac4f25e3 2003-03-19 alex Option_String( CONN_ID Idx )
331 8adff592 2005-03-19 fw static char option_txt[8];
334 ac4f25e3 2003-03-19 alex options = Conn_Options( Idx );
336 ac4f25e3 2003-03-19 alex strcpy( option_txt, "F" ); /* No idea what this means but the original ircd sends it ... */
337 c40592d2 2003-12-26 alex #ifdef ZLIB
338 ac4f25e3 2003-03-19 alex if( options & CONN_ZIP ) strcat( option_txt, "z" );
341 ac4f25e3 2003-03-19 alex return option_txt;
342 ac4f25e3 2003-03-19 alex } /* Option_String */
345 38b9cb88 2001-12-14 alex /* -eof- */