]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-write.c
New function IRC_KillClient() to kill clients
[ngircd-alex.git] / src / ngircd / irc-write.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  */
11
12 #include "portab.h"
13
14 /**
15  * @file
16  * Sending IRC commands over the network
17  */
18
19 #include "imp.h"
20 #include <assert.h>
21 #ifdef PROTOTYPES
22 #       include <stdarg.h>
23 #else
24 #       include <varargs.h>
25 #endif
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "defines.h"
30 #include "conn-func.h"
31 #include "channel.h"
32
33 #include "exp.h"
34 #include "irc-write.h"
35
36 #define SEND_TO_USER 1
37 #define SEND_TO_SERVER 2
38
39 static const char *Get_Prefix PARAMS((CLIENT *Target, CLIENT *Client));
40 static void cb_writeStrServersPrefixFlag PARAMS((CLIENT *Client,
41                                          CLIENT *Prefix, void *Buffer));
42 static void Send_Marked_Connections PARAMS((CLIENT *Prefix, const char *Buffer));
43
44 /**
45  * Send an error message to a client and enforce a penalty time.
46  *
47  * @param Client The target client.
48  * @param Format Format string.
49  * @return CONNECTED or DISCONNECTED.
50  */
51 #ifdef PROTOTYPES
52 GLOBAL bool
53 IRC_WriteErrClient( CLIENT *Client, const char *Format, ... )
54 #else
55 GLOBAL bool
56 IRC_WriteErrClient( Client, Format, va_alist )
57 CLIENT *Client;
58 const char *Format;
59 va_dcl
60 #endif
61 {
62         char buffer[1000];
63         va_list ap;
64
65         assert(Client != NULL);
66         assert(Format != NULL);
67
68 #ifdef PROTOTYPES
69         va_start(ap, Format);
70 #else
71         va_start(ap);
72 #endif
73         vsnprintf(buffer, 1000, Format, ap);
74         va_end(ap);
75
76         IRC_SetPenalty(Client, 2);
77         return IRC_WriteStrClientPrefix(Client, Client_ThisServer(),
78                                         "%s", buffer);
79 }
80
81 /**
82  * Send a message to a client.
83  *
84  * @param Client The target client.
85  * @param Format Format string.
86  * @return CONNECTED or DISCONNECTED.
87  */
88 #ifdef PROTOTYPES
89 GLOBAL bool
90 IRC_WriteStrClient( CLIENT *Client, const char *Format, ... )
91 #else
92 GLOBAL bool
93 IRC_WriteStrClient( Client, Format, va_alist )
94 CLIENT *Client;
95 const char *Format;
96 va_dcl
97 #endif
98 {
99         char buffer[1000];
100         va_list ap;
101
102         assert(Client != NULL);
103         assert(Format != NULL);
104
105 #ifdef PROTOTYPES
106         va_start(ap, Format);
107 #else
108         va_start(ap);
109 #endif
110         vsnprintf(buffer, 1000, Format, ap);
111         va_end(ap);
112
113         return IRC_WriteStrClientPrefix(Client, Client_ThisServer(),
114                                         "%s", buffer);
115 }
116
117 /**
118  * Send a message to a client using a specific prefix.
119  *
120  * @param Client The target client.
121  * @param Prefix The prefix to use.
122  * @param Format Format string.
123  * @return CONNECTED or DISCONNECTED.
124  */
125 #ifdef PROTOTYPES
126 GLOBAL bool
127 IRC_WriteStrClientPrefix(CLIENT *Client, CLIENT *Prefix, const char *Format, ...)
128 #else
129 GLOBAL bool
130 IRC_WriteStrClientPrefix(Client, Prefix, Format, va_alist)
131 CLIENT *Client;
132 CLIENT *Prefix;
133 const char *Format;
134 va_dcl
135 #endif
136 {
137         /* send text to local and remote clients */
138
139         char buffer[1000];
140         va_list ap;
141
142         assert( Client != NULL );
143         assert( Format != NULL );
144         assert( Prefix != NULL );
145
146 #ifdef PROTOTYPES
147         va_start( ap, Format );
148 #else
149         va_start( ap );
150 #endif
151         vsnprintf( buffer, 1000, Format, ap );
152         va_end( ap );
153
154         return Conn_WriteStr(Client_Conn(Client_NextHop(Client)), ":%s %s",
155                         Get_Prefix(Client_NextHop(Client), Prefix), buffer);
156 }
157
158 /**
159  * Send a message to all client in a channel.
160  *
161  * The message is only sent once per remote server.
162  *
163  * @param Client The sending client, excluded while forwarding the message.
164  * @param Channel The target channel.
165  * @param Remote If not set, the message is sent to local clients only.
166  * @param Format Format string.
167  */
168 #ifdef PROTOTYPES
169 GLOBAL void
170 IRC_WriteStrChannel(CLIENT *Client, CHANNEL *Chan, bool Remote,
171                     const char *Format, ...)
172 #else
173 GLOBAL void
174 IRC_WriteStrChannel(Client, Chan, Remote, Format, va_alist)
175 CLIENT *Client;
176 CHANNEL *Chan;
177 bool Remote;
178 const char *Format;
179 va_dcl
180 #endif
181 {
182         char buffer[1000];
183         va_list ap;
184
185         assert( Client != NULL );
186         assert( Format != NULL );
187
188 #ifdef PROTOTYPES
189         va_start( ap, Format );
190 #else
191         va_start( ap );
192 #endif
193         vsnprintf( buffer, 1000, Format, ap );
194         va_end( ap );
195
196         IRC_WriteStrChannelPrefix(Client, Chan, Client_ThisServer(),
197                                   Remote, "%s", buffer);
198 }
199
200 /**
201  * Send a message to all client in a channel using a specific prefix.
202  *
203  * The message is only sent once per remote server.
204  *
205  * @param Client The sending client, excluded while forwarding the message.
206  * @param Channel The target channel.
207  * @param Prefix The prefix to use.
208  * @param Remote If not set, the message is sent to local clients only.
209  * @param Format Format string.
210  */
211 #ifdef PROTOTYPES
212 GLOBAL void
213 IRC_WriteStrChannelPrefix(CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix,
214                           bool Remote, const char *Format, ...)
215 #else
216 GLOBAL void
217 IRC_WriteStrChannelPrefix(Client, Chan, Prefix, Remote, Format, va_alist)
218 CLIENT *Client;
219 CHANNEL *Chan;
220 CLIENT *Prefix;
221 bool Remote;
222 const char *Format;
223 va_dcl
224 #endif
225 {
226         char buffer[1000];
227         CL2CHAN *cl2chan;
228         CONN_ID conn;
229         CLIENT *c;
230         va_list ap;
231
232         assert( Client != NULL );
233         assert( Chan != NULL );
234         assert( Prefix != NULL );
235         assert( Format != NULL );
236
237 #ifdef PROTOTYPES
238         va_start( ap, Format );
239 #else
240         va_start( ap  );
241 #endif
242         vsnprintf( buffer, 1000, Format, ap );
243         va_end( ap );
244
245         Conn_ClearFlags( );
246
247         cl2chan = Channel_FirstMember( Chan );
248         while(cl2chan) {
249                 c = Channel_GetClient( cl2chan );
250                 if (!Remote) {
251                         if (Client_Conn(c) <= NONE)
252                                 c = NULL;
253                         else if(Client_Type(c) == CLIENT_SERVER)
254                                 c = NULL;
255                 }
256                 if(c)
257                         c = Client_NextHop(c);
258
259                 if(c && c != Client) {
260                         /* Ok, another Client */
261                         conn = Client_Conn(c);
262                         if (Client_Type(c) == CLIENT_SERVER)
263                                 Conn_SetFlag(conn, SEND_TO_SERVER);
264                         else
265                                 Conn_SetFlag(conn, SEND_TO_USER);
266                 }
267                 cl2chan = Channel_NextMember(Chan, cl2chan);
268         }
269         Send_Marked_Connections(Prefix, buffer);
270 }
271
272 /**
273  * Send a message to all the servers in the network.
274  *
275  * @param Client The sending client, excluded while forwarding the message.
276  * @param Format Format string.
277  */
278 #ifdef PROTOTYPES
279 GLOBAL void
280 IRC_WriteStrServers(CLIENT *ExceptOf, const char *Format, ...)
281 #else
282 GLOBAL void
283 IRC_WriteStrServers(ExceptOf, Format, va_alist)
284 CLIENT *ExceptOf;
285 const char *Format;
286 va_dcl
287 #endif
288 {
289         char buffer[1000];
290         va_list ap;
291
292         assert( Format != NULL );
293
294 #ifdef PROTOTYPES
295         va_start( ap, Format );
296 #else
297         va_start( ap );
298 #endif
299         vsnprintf( buffer, 1000, Format, ap );
300         va_end( ap );
301
302         IRC_WriteStrServersPrefix(ExceptOf, Client_ThisServer(), "%s", buffer);
303 }
304
305 /**
306  * Send a message to all the servers in the network using a specific prefix.
307  *
308  * @param Client The sending client, excluded while forwarding the message.
309  * @param Prefix The prefix to use.
310  * @param Format Format string.
311  */
312 #ifdef PROTOTYPES
313 GLOBAL void
314 IRC_WriteStrServersPrefix(CLIENT *ExceptOf, CLIENT *Prefix,
315                           const char *Format, ...)
316 #else
317 GLOBAL void
318 IRC_WriteStrServersPrefix(ExceptOf, Prefix, Format, va_alist)
319 CLIENT *ExceptOf;
320 CLIENT *Prefix;
321 const char *Format;
322 va_dcl
323 #endif
324 {
325         char buffer[1000];
326         va_list ap;
327
328         assert( Format != NULL );
329         assert( Prefix != NULL );
330
331 #ifdef PROTOTYPES
332         va_start( ap, Format );
333 #else
334         va_start( ap );
335 #endif
336         vsnprintf( buffer, 1000, Format, ap );
337         va_end( ap );
338
339         IRC_WriteStrServersPrefixFlag( ExceptOf, Prefix, '\0', "%s", buffer );
340 }
341
342 /**
343  * Send a message to all the servers in the network using a specific prefix
344  * and matching a "client flag".
345  *
346  * @param Client The sending client, excluded while forwarding the message.
347  * @param Prefix The prefix to use.
348  * @param Flag Client flag that must be set on the target.
349  * @param Format Format string.
350  */
351 #ifdef PROTOTYPES
352 GLOBAL void
353 IRC_WriteStrServersPrefixFlag(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
354                               const char *Format, ...)
355 #else
356 GLOBAL void
357 IRC_WriteStrServersPrefixFlag(ExceptOf, Prefix, Flag, Format, va_alist)
358 CLIENT *ExceptOf;
359 CLIENT *Prefix;
360 char Flag;
361 const char *Format;
362 va_dcl
363 #endif
364 {
365         char buffer[1000];
366         va_list ap;
367
368         assert( Format != NULL );
369         assert( Prefix != NULL );
370
371 #ifdef PROTOTYPES
372         va_start( ap, Format );
373 #else
374         va_start( ap );
375 #endif
376         vsnprintf( buffer, 1000, Format, ap );
377         va_end( ap );
378
379         IRC_WriteStrServersPrefixFlag_CB(ExceptOf, Prefix, Flag,
380                                          cb_writeStrServersPrefixFlag, buffer);
381 }
382
383 /**
384  * Send a message to all the servers in the network using a specific prefix
385  * and matching a "client flag" using a callback function.
386  *
387  * @param Client The sending client, excluded while forwarding the message.
388  * @param Prefix The prefix to use.
389  * @param Flag Client flag that must be set on the target.
390  * @param callback Callback function.
391  * @param Format Format string.
392  */
393 GLOBAL void
394 IRC_WriteStrServersPrefixFlag_CB(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
395                 void (*callback)(CLIENT *, CLIENT *, void *), void *cb_data)
396 {
397         CLIENT *c;
398
399         c = Client_First();
400         while(c) {
401                 if (Client_Type(c) == CLIENT_SERVER && Client_Conn(c) > NONE &&
402                     c != Client_ThisServer() && c != ExceptOf) {
403                         /* Found a target server, do the flags match? */
404                         if (Flag == '\0' || Client_HasFlag(c, Flag))
405                                 callback(c, Prefix, cb_data);
406                 }
407                 c = Client_Next(c);
408         }
409 }
410
411 /**
412  * Send a message to all "related" clients.
413  *
414  * Related clients are the one that share one ore more channels with the client
415  * sending this message.
416  *
417  * The message is only sent once per remote server.
418  *
419  * @param Client The sending client, excluded while forwarding the message.
420  * @param Prefix The prefix to use.
421  * @param Remote If not set, the message is sent to local clients only.
422  * @param Format Format string.
423  */
424 #ifdef PROTOTYPES
425 GLOBAL void
426 IRC_WriteStrRelatedPrefix(CLIENT *Client, CLIENT *Prefix, bool Remote,
427                           const char *Format, ...)
428 #else
429 GLOBAL void
430 IRC_WriteStrRelatedPrefix(Client, Prefix, Remote, Format, va_alist)
431 CLIENT *Client;
432 CLIENT *Prefix;
433 bool Remote;
434 const char *Format;
435 va_dcl
436 #endif
437 {
438         CL2CHAN *chan_cl2chan, *cl2chan;
439         char buffer[1000];
440         CHANNEL *chan;
441         CONN_ID conn;
442         va_list ap;
443         CLIENT *c;
444
445         assert( Client != NULL );
446         assert( Prefix != NULL );
447         assert( Format != NULL );
448
449 #ifdef PROTOTYPES
450         va_start( ap, Format );
451 #else
452         va_start( ap );
453 #endif
454         vsnprintf( buffer, 1000, Format, ap );
455         va_end( ap );
456
457         Conn_ClearFlags( );
458
459         chan_cl2chan = Channel_FirstChannelOf( Client );
460         while( chan_cl2chan )
461         {
462                 chan = Channel_GetChannel( chan_cl2chan );
463                 cl2chan = Channel_FirstMember( chan );
464                 while( cl2chan )
465                 {
466                         c = Channel_GetClient( cl2chan );
467                         if( ! Remote )
468                         {
469                                 if( Client_Conn( c ) <= NONE ) c = NULL;
470                                 else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
471                         }
472                         if( c ) c = Client_NextHop( c );
473
474                         if( c && ( c != Client ))
475                         {
476                                 conn = Client_Conn( c );
477                                 if( Client_Type( c ) == CLIENT_SERVER ) Conn_SetFlag( conn, SEND_TO_SERVER );
478                                 else Conn_SetFlag( conn, SEND_TO_USER );
479                         }
480                         cl2chan = Channel_NextMember( chan, cl2chan );
481                 }
482
483                 chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan );
484         }
485         Send_Marked_Connections(Prefix, buffer);
486 } /* IRC_WriteStrRelatedPrefix */
487
488 /**
489  * Send WALLOPS message.
490  *
491  * @param Client The sending client, excluded while forwarding the message.
492  * @param From The (remote) sender of the message.
493  * @param Format Format string.
494 */
495 #ifdef PROTOTYPES
496 GLOBAL void
497 IRC_SendWallops(CLIENT *Client, CLIENT *From, const char *Format, ...)
498 #else
499 GLOBAL void
500 IRC_SendWallops(Client, From, Format, va_alist )
501 CLIENT *Client;
502 CLIENT *From;
503 const char *Format;
504 va_dcl
505 #endif
506 {
507         va_list ap;
508         char msg[1000];
509         CLIENT *to;
510
511 #ifdef PROTOTYPES
512         va_start(ap, Format);
513 #else
514         va_start(ap);
515 #endif
516         vsnprintf(msg, 1000, Format, ap);
517         va_end(ap);
518
519         for (to=Client_First(); to != NULL; to=Client_Next(to)) {
520                 if (Client_Conn(to) == NONE) /* no local connection */
521                         continue;
522
523                 switch (Client_Type(to)) {
524                 case CLIENT_USER:
525                         if (Client_HasMode(to, 'w'))
526                                 IRC_WriteStrClientPrefix(to, From,
527                                                          "WALLOPS :%s", msg);
528                                 break;
529                 case CLIENT_SERVER:
530                         if (to != Client)
531                                 IRC_WriteStrClientPrefix(to, From,
532                                                          "WALLOPS :%s", msg);
533                                 break;
534                 }
535         }
536 } /* IRC_SendWallops */
537
538 /**
539  * Set a "penalty time" for an IRC client.
540  *
541  * Note: penalty times are never set for server links or remote clients!
542  *
543  * @param Client The client.
544  * @param Seconds The additional "penalty time" to enforce.
545  */
546 GLOBAL void
547 IRC_SetPenalty(CLIENT *Client, time_t Seconds)
548 {
549         CONN_ID c;
550
551         assert(Client != NULL);
552         assert(Seconds > 0);
553
554         if (Client_Type(Client) == CLIENT_SERVER)
555                 return;
556
557         c = Client_Conn(Client);
558         if (c <= NONE)
559                 return;
560
561         Conn_SetPenalty(c, Seconds);
562 } /* IRC_SetPenalty */
563
564 static const char *
565 Get_Prefix(CLIENT *Target, CLIENT *Client)
566 {
567         assert (Target != NULL);
568         assert (Client != NULL);
569
570         if (Client_Type(Target) == CLIENT_SERVER)
571                 return Client_ID(Client);
572         else
573                 return Client_MaskCloaked(Client);
574 } /* Get_Prefix */
575
576 static void
577 cb_writeStrServersPrefixFlag(CLIENT *Client, CLIENT *Prefix, void *Buffer)
578 {
579         IRC_WriteStrClientPrefix(Client, Prefix, "%s", Buffer);
580 } /* cb_writeStrServersPrefixFlag */
581
582 /**
583  * Send a message to all marked connections using a specific prefix.
584  *
585  * @param Prefix The prefix to use.
586  * @param Buffer The message to send.
587  */
588 static void
589 Send_Marked_Connections(CLIENT *Prefix, const char *Buffer)
590 {
591         CONN_ID conn;
592
593         assert(Prefix != NULL);
594         assert(Buffer != NULL);
595
596         conn = Conn_First();
597         while (conn != NONE) {
598                 if (Conn_Flag(conn) == SEND_TO_SERVER)
599                         Conn_WriteStr(conn, ":%s %s",
600                                       Client_ID(Prefix), Buffer);
601                 else if (Conn_Flag(conn) == SEND_TO_USER)
602                         Conn_WriteStr(conn, ":%s %s",
603                                       Client_MaskCloaked(Prefix), Buffer);
604                 conn = Conn_Next(conn);
605         }
606 }
607
608 /* -eof- */