Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / ircd_relay.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_relay.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25 #include "ircd_relay.h"
26 #include "channel.h"
27 #include "client.h"
28 #include "hash.h"
29 #include "ircd.h"
30 #include "ircd_chattr.h"
31 #include "ircd_reply.h"
32 #include "ircd_string.h"
33 #include "match.h"
34 #include "msg.h"
35 #include "numeric.h"
36 #include "numnicks.h"
37 #include "s_debug.h"
38 #include "s_misc.h"
39 #include "s_user.h"
40 #include "send.h"
41
42 #include <assert.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 /*
48  * This file contains message relaying functions for client and server
49  * private messages and notices
50  * TODO: This file contains a lot of cut and paste code, and needs
51  * to be cleaned up a bit. The idea is to factor out the common checks
52  * but not introduce any IsOper/IsUser/MyUser/IsServer etc. stuff.
53  */
54 void relay_channel_message(struct Client* sptr, const char* name, const char* text)
55 {
56   struct Channel* chptr;
57   assert(0 != sptr);
58   assert(0 != name);
59   assert(0 != text);
60
61   if (0 == (chptr = FindChannel(name))) {
62     send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name);
63     return;
64   }
65   /*
66    * This first: Almost never a server/service
67    */
68   if (!client_can_send_to_channel(sptr, chptr)) {
69     send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
70     return;
71   }
72   if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
73       check_target_limit(sptr, chptr, chptr->chname, 0))
74     return;
75
76   sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
77                            TOK_PRIVATE, chptr->chname, text);
78 }
79
80 void relay_channel_notice(struct Client* sptr, const char* name, const char* text)
81 {
82   struct Channel* chptr;
83   assert(0 != sptr);
84   assert(0 != name);
85   assert(0 != text);
86
87   if (0 == (chptr = FindChannel(name)))
88     return;
89   /*
90    * This first: Almost never a server/service
91    */
92   if (!client_can_send_to_channel(sptr, chptr))
93     return;
94
95   if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
96       check_target_limit(sptr, chptr, chptr->chname, 0))
97     return;  
98
99   sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
100                            TOK_NOTICE, chptr->chname, text);
101 }
102
103 void server_relay_channel_message(struct Client* sptr, const char* name, const char* text)
104 {
105   struct Channel* chptr;
106   assert(0 != sptr);
107   assert(0 != name);
108   assert(0 != text);
109
110   if (0 == (chptr = FindChannel(name))) {
111     /*
112      * XXX - do we need to send this back from a remote server?
113      */
114     send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name);
115     return;
116   }
117   /*
118    * This first: Almost never a server/service
119    * Servers may have channel services, need to check for it here
120    */
121   if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) {
122     sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
123                              TOK_PRIVATE, chptr->chname, text);
124   }
125   else
126     send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
127 }
128
129 void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text)
130 {
131   struct Channel* chptr;
132   assert(0 != sptr);
133   assert(0 != name);
134   assert(0 != text);
135
136   if (0 == (chptr = FindChannel(name)))
137     return;
138   /*
139    * This first: Almost never a server/service
140    * Servers may have channel services, need to check for it here
141    */
142   if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) {
143     sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
144                              TOK_NOTICE, chptr->chname, text);
145   }
146 }
147
148
149 void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text)
150 {
151   struct Client* acptr;
152   char*          host;
153
154   assert(0 != sptr);
155   assert(0 != name);
156   assert(0 != text);
157   assert(0 != server);
158
159   if (0 == (acptr = FindServer(server + 1))) {
160     send_error_to_client(sptr, ERR_NOSUCHNICK, name);
161     return;
162   }
163   /*
164    * NICK[%host]@server addressed? See if <server> is me first
165    */
166   if (!IsMe(acptr)) {
167     sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_PRIVATE, name, text);
168     return;
169   }
170   /*
171    * Look for an user whose NICK is equal to <name> and then
172    * check if it's hostname matches <host> and if it's a local
173    * user.
174    */
175   *server = '\0';
176   if ((host = strchr(name, '%')))
177     *host++ = '\0';
178
179   if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
180       (!EmptyString(host) && 0 != match(host, acptr->user->host))) {
181     send_error_to_client(sptr, ERR_NOSUCHNICK, name);
182     return;
183   }
184
185   *server = '@';
186   if (host)
187     *--host = '%';
188
189   if (!(is_silenced(sptr, acptr)))
190     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
191                       sptr->name, MSG_PRIVATE, name, text);
192 }
193
194 void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text)
195 {
196   struct Client* acptr;
197   char*          host;
198
199   assert(0 != sptr);
200   assert(0 != name);
201   assert(0 != text);
202   assert(0 != server);
203
204   if (0 == (acptr = FindServer(server + 1)))
205     return;
206   /*
207    * NICK[%host]@server addressed? See if <server> is me first
208    */
209   if (!IsMe(acptr)) {
210     sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_NOTICE, name, text);
211     return;
212   }
213   /*
214    * Look for an user whose NICK is equal to <name> and then
215    * check if it's hostname matches <host> and if it's a local
216    * user.
217    */
218   *server = '\0';
219   if ((host = strchr(name, '%')))
220     *host++ = '\0';
221
222   if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
223       (!EmptyString(host) && 0 != match(host, acptr->user->host)))
224     return;
225
226   *server = '@';
227   if (host)
228     *--host = '%';
229
230   if (!(is_silenced(sptr, acptr)))
231     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
232                       sptr->name, MSG_NOTICE, name, text);
233 }
234
235 void relay_private_message(struct Client* sptr, const char* name, const char* text)
236 {
237   struct Client* acptr;
238
239   assert(0 != sptr);
240   assert(0 != name);
241   assert(0 != text);
242
243   if (0 == (acptr = FindUser(name))) {
244     send_error_to_client(sptr, ERR_NOSUCHNICK, name);
245     return;
246   }
247   if (check_target_limit(sptr, acptr, acptr->name, 0) ||
248       is_silenced(sptr, acptr))
249     return;
250
251   /*
252    * send away message if user away
253    */
254   if (acptr->user && acptr->user->away)
255     sendto_one(sptr, rpl_str(RPL_AWAY),
256                me.name, sptr->name, acptr->name, acptr->user->away);
257   /*
258    * deliver the message
259    */
260   if (MyUser(acptr)) {
261     add_target(acptr, sptr);
262     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
263                       sptr->name, MSG_PRIVATE, acptr->name, text);
264   }
265   else
266     sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
267                TOK_PRIVATE, NumNick(acptr), text);
268 }
269
270 void relay_private_notice(struct Client* sptr, const char* name, const char* text)
271 {
272   struct Client* acptr;
273   assert(0 != sptr);
274   assert(0 != name);
275   assert(0 != text);
276
277   if (0 == (acptr = FindUser(name)))
278     return;
279   if (check_target_limit(sptr, acptr, acptr->name, 0) ||
280       is_silenced(sptr, acptr))
281     return;
282   /*
283    * deliver the message
284    */
285   if (MyUser(acptr)) {
286     add_target(acptr, sptr);
287     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
288                       sptr->name, MSG_NOTICE, acptr->name, text);
289   }
290   else
291     sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
292                TOK_NOTICE, NumNick(acptr), text);
293 }
294
295 void server_relay_private_message(struct Client* sptr, const char* name, const char* text)
296 {
297   struct Client* acptr;
298   assert(0 != sptr);
299   assert(0 != name);
300   assert(0 != text);
301   /*
302    * nickname addressed?
303    */
304   if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) {
305     sendto_one(sptr,
306                ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.20s]",
307                me.name, ERR_NOSUCHNICK, sptr->name, text);
308     return;
309   }
310   if (is_silenced(sptr, acptr))
311     return;
312
313   if (MyUser(acptr)) {
314     add_target(acptr, sptr);
315     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
316                       sptr->name, MSG_PRIVATE, acptr->name, text);
317   }
318   else {
319     if (IsServer(sptr))
320       sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr),
321                  TOK_PRIVATE, NumNick(acptr), text);
322     else
323       sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
324                  TOK_PRIVATE, NumNick(acptr), text);
325   }        
326 }
327
328
329 void server_relay_private_notice(struct Client* sptr, const char* name, const char* text)
330 {
331   struct Client* acptr;
332   assert(0 != sptr);
333   assert(0 != name);
334   assert(0 != text);
335   /*
336    * nickname addressed?
337    */
338   if (0 == (acptr = findNUser(name)) || !IsUser(acptr))
339     return;
340
341   if (is_silenced(sptr, acptr))
342     return;
343
344   if (MyUser(acptr)) {
345     add_target(acptr, sptr);
346     sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
347                       sptr->name, MSG_NOTICE, acptr->name, text);
348   }
349   else {
350     if (IsServer(sptr))
351       sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr), 
352                  TOK_NOTICE, NumNick(acptr), text);
353     else            
354       sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), 
355                  TOK_NOTICE, NumNick(acptr), text);
356   }              
357 }
358
359 void relay_masked_message(struct Client* sptr, const char* mask, const char* text)
360 {
361   const char* s;
362   int   host_mask = 0;
363
364   assert(0 != sptr);
365   assert(0 != mask);
366   assert(0 != text);
367   /*
368    * look for the last '.' in mask and scan forward
369    */
370   if (0 == (s = strrchr(mask, '.'))) {
371     send_error_to_client(sptr, ERR_NOTOPLEVEL, mask);
372     return;
373   }
374   while (*++s) {
375     if (*s == '.' || *s == '*' || *s == '?')
376        break;
377   }
378   if (*s == '*' || *s == '?') {
379     send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask);
380     return;
381   }
382   s = mask;
383   if ('@' == *++s) {
384     host_mask = 1;
385     ++s;
386   }
387   sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0,
388                       sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
389                       ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text);
390 }
391
392 void relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
393 {
394   const char* s;
395   int   host_mask = 0;
396
397   assert(0 != sptr);
398   assert(0 != mask);
399   assert(0 != text);
400   /*
401    * look for the last '.' in mask and scan forward
402    */
403   if (0 == (s = strrchr(mask, '.'))) {
404     send_error_to_client(sptr, ERR_NOTOPLEVEL, mask);
405     return;
406   }
407   while (*++s) {
408     if (*s == '.' || *s == '*' || *s == '?')
409        break;
410   }
411   if (*s == '*' || *s == '?') {
412     send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask);
413     return;
414   }
415   s = mask;
416   if ('@' == *++s) {
417     host_mask = 1;
418     ++s;
419   }
420   sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0,
421                       sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
422                       ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text);
423 }
424
425 void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text)
426 {
427   const char* s = mask;
428   int         host_mask = 0;
429   assert(0 != sptr);
430   assert(0 != mask);
431   assert(0 != text);
432
433   if ('@' == *++s) {
434     host_mask = 1;
435     ++s;
436   }
437   sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
438                       ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text);
439 }
440
441 void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
442 {
443   const char* s = mask;
444   int         host_mask = 0;
445   assert(0 != sptr);
446   assert(0 != mask);
447   assert(0 != text);
448
449   if ('@' == *++s) {
450     host_mask = 1;
451     ++s;
452   }
453   sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
454                       ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text);
455 }
456