f4d4361a73458495e0d8e0f706f1e58561775f19
[ngircd-alex.git] / src / ngircd / irc-write.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
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
37 #define SEND_TO_USER 1
38 #define SEND_TO_SERVER 2
39
40
41 static const char *Get_Prefix PARAMS((CLIENT *Target, CLIENT *Client));
42 static void cb_writeStrServersPrefixFlag PARAMS((CLIENT *Client,
43                                          CLIENT *Prefix, void *Buffer));
44 static void Send_Marked_Connections PARAMS((CLIENT *Prefix, const char *Buffer));
45
46
47 #ifdef PROTOTYPES
48 GLOBAL bool
49 IRC_WriteStrClient( CLIENT *Client, const char *Format, ... )
50 #else
51 GLOBAL bool
52 IRC_WriteStrClient( Client, Format, va_alist )
53 CLIENT *Client;
54 const char *Format;
55 va_dcl
56 #endif
57 {
58         char buffer[1000];
59         bool ok = CONNECTED;
60         va_list ap;
61
62         assert( Client != NULL );
63         assert( Format != NULL );
64
65 #ifdef PROTOTYPES
66         va_start( ap, Format );
67 #else
68         va_start( ap );
69 #endif
70         vsnprintf( buffer, 1000, Format, ap );
71         va_end( ap );
72
73         /* to the client itself */
74         ok = IRC_WriteStrClientPrefix( Client, Client_ThisServer( ), "%s", buffer );
75
76         return ok;
77 } /* IRC_WriteStrClient */
78
79
80 #ifdef PROTOTYPES
81 GLOBAL bool
82 IRC_WriteStrClientPrefix(CLIENT *Client, CLIENT *Prefix, const char *Format, ...)
83 #else
84 GLOBAL bool
85 IRC_WriteStrClientPrefix(Client, Prefix, Format, va_alist)
86 CLIENT *Client;
87 CLIENT *Prefix;
88 const char *Format;
89 va_dcl
90 #endif
91 {
92         /* send text to local and remote clients */
93
94         char buffer[1000];
95         va_list ap;
96
97         assert( Client != NULL );
98         assert( Format != NULL );
99         assert( Prefix != NULL );
100
101 #ifdef PROTOTYPES
102         va_start( ap, Format );
103 #else
104         va_start( ap );
105 #endif
106         vsnprintf( buffer, 1000, Format, ap );
107         va_end( ap );
108
109         return Conn_WriteStr(Client_Conn(Client_NextHop(Client)), ":%s %s",
110                         Get_Prefix(Client_NextHop(Client), Prefix), buffer);
111 } /* IRC_WriteStrClientPrefix */
112
113
114 #ifdef PROTOTYPES
115 GLOBAL void
116 IRC_WriteStrChannel(CLIENT *Client, CHANNEL *Chan, bool Remote,
117                     const char *Format, ...)
118 #else
119 GLOBAL void
120 IRC_WriteStrChannel(Client, Chan, Remote, Format, va_alist)
121 CLIENT *Client;
122 CHANNEL *Chan;
123 bool Remote;
124 const char *Format;
125 va_dcl
126 #endif
127 {
128         char buffer[1000];
129         va_list ap;
130
131         assert( Client != NULL );
132         assert( Format != NULL );
133
134 #ifdef PROTOTYPES
135         va_start( ap, Format );
136 #else
137         va_start( ap );
138 #endif
139         vsnprintf( buffer, 1000, Format, ap );
140         va_end( ap );
141
142         IRC_WriteStrChannelPrefix(Client, Chan, Client_ThisServer(),
143                                   Remote, "%s", buffer );
144 } /* IRC_WriteStrChannel */
145
146
147 /**
148  * send message to all clients in the same channel, but only send message
149  * once per remote server.
150  */
151 #ifdef PROTOTYPES
152 GLOBAL void
153 IRC_WriteStrChannelPrefix(CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix,
154                           bool Remote, const char *Format, ...)
155 #else
156 GLOBAL void
157 IRC_WriteStrChannelPrefix(Client, Chan, Prefix, Remote, Format, va_alist)
158 CLIENT *Client;
159 CHANNEL *Chan;
160 CLIENT *Prefix;
161 bool Remote;
162 const char *Format;
163 va_dcl
164 #endif
165 {
166         char buffer[1000];
167         CL2CHAN *cl2chan;
168         CONN_ID conn;
169         CLIENT *c;
170         va_list ap;
171
172         assert( Client != NULL );
173         assert( Chan != NULL );
174         assert( Prefix != NULL );
175         assert( Format != NULL );
176
177 #ifdef PROTOTYPES
178         va_start( ap, Format );
179 #else
180         va_start( ap  );
181 #endif
182         vsnprintf( buffer, 1000, Format, ap );
183         va_end( ap );
184
185         Conn_ClearFlags( );
186
187         cl2chan = Channel_FirstMember( Chan );
188         while( cl2chan )
189         {
190                 c = Channel_GetClient( cl2chan );
191                 if( ! Remote )
192                 {
193                         if( Client_Conn( c ) <= NONE ) c = NULL;
194                         else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
195                 }
196                 if( c ) c = Client_NextHop( c );
197
198                 if( c && ( c != Client ))
199                 {
200                         /* Ok, another Client */
201                         conn = Client_Conn( c );
202                         if( Client_Type( c ) == CLIENT_SERVER ) Conn_SetFlag( conn, SEND_TO_SERVER );
203                         else Conn_SetFlag( conn, SEND_TO_USER );
204                 }
205                 cl2chan = Channel_NextMember( Chan, cl2chan );
206         }
207         Send_Marked_Connections(Prefix, buffer);
208 } /* IRC_WriteStrChannelPrefix */
209
210
211 #ifdef PROTOTYPES
212 GLOBAL void
213 IRC_WriteStrServers(CLIENT *ExceptOf, const char *Format, ...)
214 #else
215 GLOBAL void
216 IRC_WriteStrServers(ExceptOf, Format, va_alist)
217 CLIENT *ExceptOf;
218 const char *Format;
219 va_dcl
220 #endif
221 {
222         char buffer[1000];
223         va_list ap;
224
225         assert( Format != NULL );
226
227 #ifdef PROTOTYPES
228         va_start( ap, Format );
229 #else
230         va_start( ap );
231 #endif
232         vsnprintf( buffer, 1000, Format, ap );
233         va_end( ap );
234
235         IRC_WriteStrServersPrefix( ExceptOf, Client_ThisServer( ), "%s", buffer );
236 } /* IRC_WriteStrServers */
237
238
239 #ifdef PROTOTYPES
240 GLOBAL void
241 IRC_WriteStrServersPrefix(CLIENT *ExceptOf, CLIENT *Prefix,
242                           const char *Format, ...)
243 #else
244 GLOBAL void
245 IRC_WriteStrServersPrefix(ExceptOf, Prefix, Format, va_alist)
246 CLIENT *ExceptOf;
247 CLIENT *Prefix;
248 const char *Format;
249 va_dcl
250 #endif
251 {
252         char buffer[1000];
253         va_list ap;
254
255         assert( Format != NULL );
256         assert( Prefix != NULL );
257
258 #ifdef PROTOTYPES
259         va_start( ap, Format );
260 #else
261         va_start( ap );
262 #endif
263         vsnprintf( buffer, 1000, Format, ap );
264         va_end( ap );
265
266         IRC_WriteStrServersPrefixFlag( ExceptOf, Prefix, '\0', "%s", buffer );
267 } /* IRC_WriteStrServersPrefix */
268
269
270 #ifdef PROTOTYPES
271 GLOBAL void
272 IRC_WriteStrServersPrefixFlag(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
273                               const char *Format, ...)
274 #else
275 GLOBAL void
276 IRC_WriteStrServersPrefixFlag(ExceptOf, Prefix, Flag, Format, va_alist)
277 CLIENT *ExceptOf;
278 CLIENT *Prefix;
279 char Flag;
280 const char *Format;
281 va_dcl
282 #endif
283 {
284         char buffer[1000];
285         va_list ap;
286
287         assert( Format != NULL );
288         assert( Prefix != NULL );
289
290 #ifdef PROTOTYPES
291         va_start( ap, Format );
292 #else
293         va_start( ap );
294 #endif
295         vsnprintf( buffer, 1000, Format, ap );
296         va_end( ap );
297
298         IRC_WriteStrServersPrefixFlag_CB(ExceptOf, Prefix, Flag,
299                                          cb_writeStrServersPrefixFlag, buffer);
300 } /* IRC_WriteStrServersPrefixFlag */
301
302
303 GLOBAL void
304 IRC_WriteStrServersPrefixFlag_CB(CLIENT *ExceptOf, CLIENT *Prefix, char Flag,
305                 void (*callback)(CLIENT *, CLIENT *, void *), void *cb_data)
306 {
307         CLIENT *c;
308
309         c = Client_First();
310         while(c) {
311                 if (Client_Type(c) == CLIENT_SERVER && Client_Conn(c) > NONE &&
312                     c != Client_ThisServer() && c != ExceptOf) {
313                         /* Found a target server, do the flags match? */
314                         if (Flag == '\0' || Client_HasFlag(c, Flag))
315                                 callback(c, Prefix, cb_data);
316                 }
317                 c = Client_Next(c);
318         }
319 } /* IRC_WriteStrServersPrefixFlag */
320
321
322 /**
323  * send message to all clients that are in the same channels as the client sending this message.
324  * only send message once per remote server.
325  */
326 #ifdef PROTOTYPES
327 GLOBAL void
328 IRC_WriteStrRelatedPrefix(CLIENT *Client, CLIENT *Prefix, bool Remote,
329                           const char *Format, ...)
330 #else
331 GLOBAL void
332 IRC_WriteStrRelatedPrefix(Client, Prefix, Remote, Format, va_alist)
333 CLIENT *Client;
334 CLIENT *Prefix;
335 bool Remote;
336 const char *Format;
337 va_dcl
338 #endif
339 {
340         CL2CHAN *chan_cl2chan, *cl2chan;
341         char buffer[1000];
342         CHANNEL *chan;
343         CONN_ID conn;
344         va_list ap;
345         CLIENT *c;
346
347         assert( Client != NULL );
348         assert( Prefix != NULL );
349         assert( Format != NULL );
350
351 #ifdef PROTOTYPES
352         va_start( ap, Format );
353 #else
354         va_start( ap );
355 #endif
356         vsnprintf( buffer, 1000, Format, ap );
357         va_end( ap );
358
359         Conn_ClearFlags( );
360
361         chan_cl2chan = Channel_FirstChannelOf( Client );
362         while( chan_cl2chan )
363         {
364                 chan = Channel_GetChannel( chan_cl2chan );
365                 cl2chan = Channel_FirstMember( chan );
366                 while( cl2chan )
367                 {
368                         c = Channel_GetClient( cl2chan );
369                         if( ! Remote )
370                         {
371                                 if( Client_Conn( c ) <= NONE ) c = NULL;
372                                 else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
373                         }
374                         if( c ) c = Client_NextHop( c );
375
376                         if( c && ( c != Client ))
377                         {
378                                 conn = Client_Conn( c );
379                                 if( Client_Type( c ) == CLIENT_SERVER ) Conn_SetFlag( conn, SEND_TO_SERVER );
380                                 else Conn_SetFlag( conn, SEND_TO_USER );
381                         }
382                         cl2chan = Channel_NextMember( chan, cl2chan );
383                 }
384
385                 chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan );
386         }
387         Send_Marked_Connections(Prefix, buffer);
388 } /* IRC_WriteStrRelatedPrefix */
389
390
391 /**
392  * Send WALLOPS message.
393  */
394 #ifdef PROTOTYPES
395 GLOBAL void
396 IRC_SendWallops(CLIENT *Client, CLIENT *From, const char *Format, ...)
397 #else
398 GLOBAL void
399 IRC_SendWallops(Client, From, Format, va_alist )
400 CLIENT *Client;
401 CLIENT *From;
402 const char *Format;
403 va_dcl
404 #endif
405 {
406         va_list ap;
407         char msg[1000];
408         CLIENT *to;
409
410 #ifdef PROTOTYPES
411         va_start(ap, Format);
412 #else
413         va_start(ap);
414 #endif
415         vsnprintf(msg, 1000, Format, ap);
416         va_end(ap);
417
418         for (to=Client_First(); to != NULL; to=Client_Next(to)) {
419                 if (Client_Conn(to) == NONE) /* no local connection */
420                         continue;
421
422                 switch (Client_Type(to)) {
423                 case CLIENT_USER:
424                         if (Client_HasMode(to, 'w'))
425                                 IRC_WriteStrClientPrefix(to, From,
426                                                          "WALLOPS :%s", msg);
427                                 break;
428                 case CLIENT_SERVER:
429                         if (to != Client)
430                                 IRC_WriteStrClientPrefix(to, From,
431                                                          "WALLOPS :%s", msg);
432                                 break;
433                 }
434         }
435 } /* IRC_SendWallops */
436
437
438 GLOBAL void
439 IRC_SetPenalty( CLIENT *Client, time_t Seconds )
440 {
441         CONN_ID c;
442
443         assert( Client != NULL );
444         assert( Seconds > 0 );
445
446         if( Client_Type( Client ) == CLIENT_SERVER ) return;
447
448         c = Client_Conn( Client );
449         if (c > NONE)
450                 Conn_SetPenalty(c, Seconds);
451 } /* IRC_SetPenalty */
452
453
454 static const char *
455 Get_Prefix(CLIENT *Target, CLIENT *Client)
456 {
457         assert (Target != NULL);
458         assert (Client != NULL);
459
460         if (Client_Type(Target) == CLIENT_SERVER)
461                 return Client_ID(Client);
462         else
463                 return Client_MaskCloaked(Client);
464 } /* Get_Prefix */
465
466
467 static void
468 cb_writeStrServersPrefixFlag(CLIENT *Client, CLIENT *Prefix, void *Buffer)
469 {
470         IRC_WriteStrClientPrefix(Client, Prefix, "%s", Buffer);
471 } /* cb_writeStrServersPrefixFlag */
472
473
474 static void
475 Send_Marked_Connections(CLIENT *Prefix, const char *Buffer)
476 {
477         CONN_ID conn;
478
479         assert(Prefix != NULL);
480         assert(Buffer != NULL);
481
482         conn = Conn_First();
483         while (conn != NONE) {
484                 if (Conn_Flag(conn) == SEND_TO_SERVER)
485                         Conn_WriteStr(conn, ":%s %s",
486                                       Client_ID(Prefix), Buffer);
487                 else if (Conn_Flag(conn) == SEND_TO_USER)
488                         Conn_WriteStr(conn, ":%s %s",
489                                       Client_MaskCloaked(Prefix), Buffer);
490                 conn = Conn_Next( conn );
491         }
492 }
493
494
495 /* -eof- */