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