Author: Kev <klmitch@mit.edu>
[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_reply(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_reply(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   sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, sptr->from,
77                            SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, 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   sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, sptr->from,
100                            SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, 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_reply(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     sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, sptr->from,
123                              SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text);
124   }
125   else
126     send_reply(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     sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, sptr->from,
144                              SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, 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_reply(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     sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", 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_reply(sptr, ERR_NOSUCHNICK, name);
182     return;
183   }
184
185   *server = '@';
186   if (host)
187     *--host = '%';
188
189   if (!(is_silenced(sptr, acptr)))
190     sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
191 }
192
193 void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text)
194 {
195   struct Client* acptr;
196   char*          host;
197
198   assert(0 != sptr);
199   assert(0 != name);
200   assert(0 != text);
201   assert(0 != server);
202
203   if (0 == (acptr = FindServer(server + 1)))
204     return;
205   /*
206    * NICK[%host]@server addressed? See if <server> is me first
207    */
208   if (!IsMe(acptr)) {
209     sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
210     return;
211   }
212   /*
213    * Look for an user whose NICK is equal to <name> and then
214    * check if it's hostname matches <host> and if it's a local
215    * user.
216    */
217   *server = '\0';
218   if ((host = strchr(name, '%')))
219     *host++ = '\0';
220
221   if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
222       (!EmptyString(host) && 0 != match(host, acptr->user->host)))
223     return;
224
225   *server = '@';
226   if (host)
227     *--host = '%';
228
229   if (!(is_silenced(sptr, acptr)))
230     sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
231 }
232
233 void relay_private_message(struct Client* sptr, const char* name, const char* text)
234 {
235   struct Client* acptr;
236
237   assert(0 != sptr);
238   assert(0 != name);
239   assert(0 != text);
240
241   if (0 == (acptr = FindUser(name))) {
242     send_reply(sptr, ERR_NOSUCHNICK, name);
243     return;
244   }
245   if (check_target_limit(sptr, acptr, acptr->name, 0) ||
246       is_silenced(sptr, acptr))
247     return;
248
249   /*
250    * send away message if user away
251    */
252   if (acptr->user && acptr->user->away)
253     send_reply(sptr, RPL_AWAY, acptr->name, acptr->user->away);
254   /*
255    * deliver the message
256    */
257   if (MyUser(acptr))
258     add_target(acptr, sptr);
259
260   sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
261 }
262
263 void relay_private_notice(struct Client* sptr, const char* name, const char* text)
264 {
265   struct Client* acptr;
266   assert(0 != sptr);
267   assert(0 != name);
268   assert(0 != text);
269
270   if (0 == (acptr = FindUser(name)))
271     return;
272   if (check_target_limit(sptr, acptr, acptr->name, 0) ||
273       is_silenced(sptr, acptr))
274     return;
275   /*
276    * deliver the message
277    */
278   if (MyUser(acptr))
279     add_target(acptr, sptr);
280
281   sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
282 }
283
284 void server_relay_private_message(struct Client* sptr, const char* name, const char* text)
285 {
286   struct Client* acptr;
287   assert(0 != sptr);
288   assert(0 != name);
289   assert(0 != text);
290   /*
291    * nickname addressed?
292    */
293   if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) {
294     send_reply(sptr, RPL_EXPLICIT | ERR_NOSUCHNICK, "* :Target left UnderNet. "
295                "Failed to deliver: [%.20s]", text);
296     return;
297   }
298   if (is_silenced(sptr, acptr))
299     return;
300
301   if (MyUser(acptr))
302     add_target(acptr, sptr);
303
304   sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
305 }
306
307
308 void server_relay_private_notice(struct Client* sptr, const char* name, const char* text)
309 {
310   struct Client* acptr;
311   assert(0 != sptr);
312   assert(0 != name);
313   assert(0 != text);
314   /*
315    * nickname addressed?
316    */
317   if (0 == (acptr = findNUser(name)) || !IsUser(acptr))
318     return;
319
320   if (is_silenced(sptr, acptr))
321     return;
322
323   if (MyUser(acptr))
324     add_target(acptr, sptr);
325
326   sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
327 }
328
329 void relay_masked_message(struct Client* sptr, const char* mask, const char* text)
330 {
331   const char* s;
332   int   host_mask = 0;
333
334   assert(0 != sptr);
335   assert(0 != mask);
336   assert(0 != text);
337   /*
338    * look for the last '.' in mask and scan forward
339    */
340   if (0 == (s = strrchr(mask, '.'))) {
341     send_reply(sptr, ERR_NOTOPLEVEL, mask);
342     return;
343   }
344   while (*++s) {
345     if (*s == '.' || *s == '*' || *s == '?')
346        break;
347   }
348   if (*s == '*' || *s == '?') {
349     send_reply(sptr, ERR_WILDTOPLEVEL, mask);
350     return;
351   }
352   s = mask;
353   if ('@' == *++s) {
354     host_mask = 1;
355     ++s;
356   }
357
358   sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
359                          IsServer(sptr->from) ? sptr->from : 0,
360                          host_mask ? MATCH_HOST : MATCH_SERVER,
361                          "%s :%s", mask, text);
362 }
363
364 void relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
365 {
366   const char* s;
367   int   host_mask = 0;
368
369   assert(0 != sptr);
370   assert(0 != mask);
371   assert(0 != text);
372   /*
373    * look for the last '.' in mask and scan forward
374    */
375   if (0 == (s = strrchr(mask, '.'))) {
376     send_reply(sptr, ERR_NOTOPLEVEL, mask);
377     return;
378   }
379   while (*++s) {
380     if (*s == '.' || *s == '*' || *s == '?')
381        break;
382   }
383   if (*s == '*' || *s == '?') {
384     send_reply(sptr, ERR_WILDTOPLEVEL, mask);
385     return;
386   }
387   s = mask;
388   if ('@' == *++s) {
389     host_mask = 1;
390     ++s;
391   }
392
393   sendcmdto_match_butone(sptr, CMD_NOTICE, s,
394                          IsServer(sptr->from) ? sptr->from : 0,
395                          host_mask ? MATCH_HOST : MATCH_SERVER,
396                          "%s :%s", mask, text);
397 }
398
399 void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text)
400 {
401   const char* s = mask;
402   int         host_mask = 0;
403   assert(0 != sptr);
404   assert(0 != mask);
405   assert(0 != text);
406
407   if ('@' == *++s) {
408     host_mask = 1;
409     ++s;
410   }
411   sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
412                          IsServer(sptr->from) ? sptr->from : 0,
413                          host_mask ? MATCH_HOST : MATCH_SERVER,
414                          "%s :%s", mask, text);
415 }
416
417 void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
418 {
419   const char* s = mask;
420   int         host_mask = 0;
421   assert(0 != sptr);
422   assert(0 != mask);
423   assert(0 != text);
424
425   if ('@' == *++s) {
426     host_mask = 1;
427     ++s;
428   }
429   sendcmdto_match_butone(sptr, CMD_NOTICE, s,
430                          IsServer(sptr->from) ? sptr->from : 0,
431                          host_mask ? MATCH_HOST : MATCH_SERVER,
432                          "%s :%s", mask, text);
433 }
434