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