This commit was generated by cvs2svn to compensate for changes in r2,
[ircu2.10.12-pk.git] / ircd / querycmds.c
1 /*
2  * IRC - Internet Relay Chat, ircd/querycmds.c (formerly ircd/s_serv.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
24 #include "sys.h"
25 #include <sys/stat.h>
26 #if HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #include <stdlib.h>
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include "h.h"
34 #include "struct.h"
35 #include "parse.h"
36 #include "send.h"
37 #include "s_err.h"
38 #include "numeric.h"
39 #include "ircd.h"
40 #include "s_user.h"
41 #include "version.h"
42 #include "s_bsd.h"
43 #include "s_misc.h"
44 #include "match.h"
45 #include "s_serv.h"
46 #include "msg.h"
47 #include "channel.h"
48 #include "numnicks.h"
49 #include "userload.h"
50 #include "s_conf.h"
51 #include "support.h"
52 #include "querycmds.h"
53
54 RCSTAG_CC("$Id$");
55
56 /*
57  * m_functions execute protocol messages on this server:
58  *
59  *   cptr    is always NON-NULL, pointing to a *LOCAL* client
60  *           structure (with an open socket connected!). This
61  *           identifies the physical socket where the message
62  *           originated (or which caused the m_function to be
63  *           executed--some m_functions may call others...).
64  *
65  *   sptr    is the source of the message, defined by the
66  *           prefix part of the message if present. If not
67  *           or prefix not found, then sptr==cptr.
68  *
69  *           (!IsServer(cptr)) => (cptr == sptr), because
70  *           prefixes are taken *only* from servers...
71  *
72  *           (IsServer(cptr))
73  *                   (sptr == cptr) => the message didn't
74  *                   have the prefix.
75  *
76  *                   (sptr != cptr && IsServer(sptr) means
77  *                   the prefix specified servername. (?)
78  *
79  *                   (sptr != cptr && !IsServer(sptr) means
80  *                   that message originated from a remote
81  *                   user (not local).
82  *
83  *           combining
84  *
85  *           (!IsServer(sptr)) means that, sptr can safely
86  *           taken as defining the target structure of the
87  *           message in this server.
88  *
89  *   *Always* true (if 'parse' and others are working correct):
90  *
91  *   1)      sptr->from == cptr  (note: cptr->from == cptr)
92  *
93  *   2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
94  *           *cannot* be a local connection, unless it's
95  *           actually cptr!). [MyConnect(x) should probably
96  *           be defined as (x == x->from) --msa ]
97  *
98  *   parc    number of variable parameter strings (if zero,
99  *           parv is allowed to be NULL)
100  *
101  *   parv    a NULL terminated list of parameter pointers,
102  *
103  *                   parv[0], sender (prefix string), if not present
104  *                           this points to an empty string.
105  *                   parv[1]...parv[parc-1]
106  *                           pointers to additional parameters
107  *                   parv[parc] == NULL, *always*
108  *
109  *           note:   it is guaranteed that parv[0]..parv[parc-1] are all
110  *                   non-NULL pointers.
111  */
112
113 /*
114  * m_version
115  *
116  *   parv[0] = sender prefix
117  *   parv[1] = remote server
118  */
119 int m_version(aClient *cptr, aClient *sptr, int parc, char *parv[])
120 {
121   Reg1 aClient *acptr;
122
123   if (MyConnect(sptr) && parc > 1)
124   {
125     if (!(acptr = find_match_server(parv[1])))
126     {
127       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
128       return 0;
129     }
130     parv[1] = acptr->name;
131   }
132
133   if (hunt_server(0, cptr, sptr, ":%s VERSION :%s", 1, parc, parv) ==
134       HUNTED_ISME)
135     sendto_one(sptr, rpl_str(RPL_VERSION),
136         me.name, parv[0], version, debugmode, me.name, serveropts);
137
138   return 0;
139 }
140
141 /*
142  * m_info
143  *
144  * parv[0] = sender prefix
145  * parv[1] = servername
146  */
147 int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[])
148 {
149   const char **text = infotext;
150
151   if (hunt_server(1, cptr, sptr, ":%s INFO :%s", 1, parc, parv) == HUNTED_ISME)
152   {
153     while (text[2])
154     {
155       if (!IsOper(sptr))
156         sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
157       text++;
158     }
159     if (IsOper(sptr))
160     {
161       while (*text)
162         sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
163       sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
164     }
165     sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
166         me.name, RPL_INFO, parv[0], creation, generation);
167     sendto_one(sptr, ":%s %d %s :On-line since %s",
168         me.name, RPL_INFO, parv[0], myctime(me.firsttime));
169     sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
170   }
171   return 0;
172 }
173
174 /*
175  * m_links
176  *
177  * parv[0] = sender prefix
178  * parv[1] = servername mask
179  *
180  * or
181  *
182  * parv[0] = sender prefix
183  * parv[1] = server to query
184  * parv[2] = servername mask
185  */
186 int m_links(aClient *cptr, aClient *sptr, int parc, char *parv[])
187 {
188   char *mask;
189   aClient *acptr;
190
191   if (parc > 2)
192   {
193     if (hunt_server(1, cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv) !=
194         HUNTED_ISME)
195       return 0;
196     mask = parv[2];
197   }
198   else
199     mask = parc < 2 ? NULL : parv[1];
200
201   for (acptr = client, collapse(mask); acptr; acptr = acptr->next)
202   {
203     if (!IsServer(acptr) && !IsMe(acptr))
204       continue;
205     if (!BadPtr(mask) && match(mask, acptr->name))
206       continue;
207     sendto_one(sptr, rpl_str(RPL_LINKS),
208         me.name, parv[0], acptr->name, acptr->serv->up->name,
209 #ifndef GODMODE
210         acptr->hopcount, acptr->serv->prot,
211 #else /* GODMODE */
212         acptr->hopcount, acptr->serv->prot, acptr->serv->timestamp,
213         NumServ(acptr),
214 #endif /* GODMODE */
215         (acptr->info[0] ? acptr->info : "(Unknown Location)"));
216   }
217
218   sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
219       BadPtr(mask) ? "*" : mask);
220   return 0;
221 }
222
223 /*
224  * m_help
225  *
226  * parv[0] = sender prefix
227  */
228 int m_help(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
229 {
230   int i;
231
232   for (i = 0; msgtab[i].cmd; i++)
233     sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], msgtab[i].cmd);
234   return 0;
235 }
236
237 /* Counters of client/servers etc. */
238 struct lusers_st nrof;
239
240 void init_counters(void)
241 {
242   memset(&nrof, 0, sizeof(nrof));
243   nrof.servers = 1;
244 }
245
246 /*
247  * m_lusers
248  *
249  * parv[0] = sender
250  * parv[1] = ignored
251  * parv[2] = server to query
252  */
253 int m_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
254 {
255   if (parc > 2)
256     if (hunt_server(1, cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv) !=
257         HUNTED_ISME)
258       return 0;
259
260   sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
261       nrof.clients - nrof.inv_clients, nrof.inv_clients, nrof.servers);
262   if (nrof.opers)
263     sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], nrof.opers);
264   if (nrof.unknowns > 0)
265     sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0],
266         nrof.unknowns);
267   if (nrof.channels > 0)
268     sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0],
269         nrof.channels);
270   sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], nrof.local_clients,
271       nrof.local_servers);
272
273   if (MyUser(sptr) || Protocol(cptr) < 10)
274     sendto_one(sptr,
275         ":%s NOTICE %s :Highest connection count: %d (%d clients)",
276         me.name, parv[0], max_connection_count, max_client_count);
277   else
278     sendto_one(sptr,
279         "%s NOTICE %s%s :Highest connection count: %d (%d clients)",
280         NumServ(&me), NumNick(sptr), max_connection_count, max_client_count);
281
282   return 0;
283 }
284
285 /*
286  * m_admin
287  *
288  * parv[0] = sender prefix
289  * parv[1] = servername
290  */
291 int m_admin(aClient *cptr, aClient *sptr, int parc, char *parv[])
292 {
293   aConfItem *aconf;
294
295   if (MyConnect(sptr) && parc > 1)
296   {
297     aClient *acptr;
298     if (!(acptr = find_match_server(parv[1])))
299     {
300       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
301       return 0;
302     }
303     parv[1] = acptr->name;
304   }
305   if (hunt_server(0, cptr, sptr, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME)
306     return 0;
307   if ((aconf = find_admin()))
308   {
309     sendto_one(sptr, rpl_str(RPL_ADMINME), me.name, parv[0], me.name);
310     sendto_one(sptr, rpl_str(RPL_ADMINLOC1), me.name, parv[0], aconf->host);
311     sendto_one(sptr, rpl_str(RPL_ADMINLOC2), me.name, parv[0], aconf->passwd);
312     sendto_one(sptr, rpl_str(RPL_ADMINEMAIL), me.name, parv[0], aconf->name);
313   }
314   else
315     sendto_one(sptr, err_str(ERR_NOADMININFO), me.name, parv[0], me.name);
316   return 0;
317 }
318
319 /*
320  * m_motd
321  *
322  * parv[0] - sender prefix
323  * parv[1] - servername
324  *
325  * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
326  * T line patch - display motd based on hostmask
327  * modified again 7 sep 97 by Ghostwolf with code and ideas 
328  * stolen from comstud & Xorath.  All motd files are read into
329  * memory in read_motd() in s_conf.c
330  *
331  * When NODEFAULTMOTD is defined, then it is possible that
332  * sptr == NULL, which means that this function is called from
333  * register_user.
334  */
335 int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
336 {
337   struct tm *tm = &motd_tm;     /* Default: Most general case */
338   atrecord *ptr;
339   int count;
340   register aMotdItem *temp;
341
342 #ifdef NODEFAULTMOTD
343   int no_motd;
344
345   if (sptr)
346   {
347     no_motd = 0;
348 #endif
349     if (hunt_server(0, cptr, sptr, ":%s MOTD :%s", 1, parc,
350         parv) != HUNTED_ISME)
351       return 0;
352 #ifdef NODEFAULTMOTD
353   }
354   else
355   {
356     sptr = cptr;
357     no_motd = 1;
358   }
359 #endif
360
361   /*
362    * Find out if this is a remote query or if we have a T line for our hostname
363    */
364   if (IsServer(cptr))
365   {
366     tm = NULL;                  /* Remote MOTD */
367     temp = rmotd;
368   }
369   else
370   {
371     for (ptr = tdata; ptr; ptr = ptr->next)
372     {
373       if (!match(ptr->hostmask, cptr->sockhost))
374         break;
375     }
376     if (ptr)
377     {
378       temp = ptr->tmotd;
379       tm = &ptr->tmotd_tm;
380     }
381     else
382       temp = motd;
383   }
384   if (temp == NULL)
385   {
386     sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
387     return 0;
388   }
389 #ifdef NODEFAULTMOTD
390   if (!no_motd)
391   {
392 #endif
393     if (tm)                     /* Not remote? */
394     {
395       sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
396       sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
397           parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
398           tm->tm_hour, tm->tm_min);
399       count = 100;
400     }
401     else
402       count = 3;
403     for (; temp; temp = temp->next)
404     {
405       sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
406       if (--count == 0)
407         break;
408     }
409 #ifdef NODEFAULTMOTD
410   }
411   else
412   {
413     sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
414     sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_MOTD, parv[0],
415         "\ 2Type /MOTD to read the AUP before continuing using this service.\ 2");
416     sendto_one(sptr,
417         ":%s %d %s :The message of the day was last changed: %d/%d/%d", me.name,
418         RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
419   }
420 #endif
421   sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
422   return 0;
423 }