- The big forward port. I probably broke lots of stuff, so please look over any
[ircu2.10.12-pk.git] / ircd / map.c
1 /*
2  * IRC - Internet Relay Chat, ircd/map.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  * Copyright (C) 2002 Joseph Bongaarts <foxxe@wtfs.net>
6  *
7  * See file AUTHORS in IRC package for additional names of
8  * the programmers.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 1, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * $Id$
25  */
26
27 #include "config.h"
28
29 #include "client.h"
30 #include "ircd.h"
31 #include "ircd_defs.h"
32 #include "ircd_policy.h"
33 #include "ircd_reply.h"
34 #include "ircd_snprintf.h"
35 #include "ircd_string.h"
36 #include "ircd_alloc.h"
37 #include "hash.h"
38 #include "list.h"
39 #include "match.h"
40 #include "msg.h"
41 #include "numeric.h"
42 #include "s_user.h"
43 #include "s_serv.h"
44 #include "send.h"
45 #include "querycmds.h"
46 #include "map.h"
47
48 #include <assert.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #if defined(HEAD_IN_SAND_MAP) || defined(HEAD_IN_SAND_LINKS)
53
54 static struct Map *MapList = 0;
55
56 /* Add a server to the map list. */
57 static void map_add(struct Client *server)
58 {
59   struct Map *map = (struct Map *)MyMalloc(sizeof(struct Map));
60
61   assert(IsServer(server));
62   assert(!IsHub(server));
63   assert(!IsService(server));
64
65   map->lasttime = TStime();
66   strcpy(map->name, cli_name(server));
67   strcpy(map->info, cli_info(server));
68   map->prot = Protocol(server);
69   map->maxclients = cli_serv(server)->clients;
70
71   map->prev = 0;
72   map->next = MapList;
73
74   if(MapList)
75     MapList->prev = map;
76   
77   MapList = map;
78 }
79
80 /* Remove a server from the map list */
81 static void map_remove(struct Map *cptr)
82 {
83   assert(cptr != 0);
84   
85   if(cptr->next)
86     cptr->next->prev = cptr->prev;
87   
88   if(cptr->prev)
89     cptr->prev->next = cptr->next;
90   
91   if(MapList == cptr)
92     MapList = cptr->next;
93
94   MyFree(cptr);
95
96 }
97
98 /* Update a server in the list. Called when a server connects
99  * splits, or we haven't checked in more than a week. */
100 void map_update(struct Client *cptr)
101 {
102   struct Map *map = 0;
103
104   assert(IsServer(cptr));
105
106   /* Find the server in the list and update it */ 
107   for(map = MapList; map; map = map->next)
108   {
109     /* Show max clients not current, otherwise a split can be detected. */
110     if(!ircd_strcmp(cli_name(cptr), map->name)) 
111     { 
112       map->lasttime = TStime();
113       map->prot = Protocol(cptr);
114       strcpy(map->info, cli_info(cptr));
115       if(map->maxclients < cli_serv(cptr)->clients) 
116         map->maxclients = cli_serv(cptr)->clients;  
117       break;
118     }
119   }
120
121   /* We do this check after finding a matching map because
122    * a client server can become a hub or service (such as 
123    * santaclara)
124    */
125   if(IsHub(cptr) || IsService(cptr))
126   {
127     if(map)
128       map_remove(map);
129     return;
130   }
131
132   /* If we haven't seen it before, add it to the list. */
133   if(!map)
134     map_add(cptr);
135 }
136 #endif /* HEAD_IN_SAND_MAP || HEAD_IN_SAND_LINKS*/ 
137
138 #ifdef HEAD_IN_SAND_MAP
139
140 void map_dump_head_in_sand(struct Client *cptr)
141 {
142   struct Map *map = 0;
143   struct Map *smap = 0;
144   struct Client *acptr = 0;
145
146   /* Send me first */
147   send_reply(cptr, RPL_MAP, "", "", cli_name(&me), "", UserStats.local_clients);
148
149   for(map = MapList; map; map = smap)
150   {
151     smap = map->next;
152
153     /* Don't show servers we haven't seen in more than a week */
154     if(map->lasttime < TStime() - MAP_CACHE_TIME)
155     {
156       acptr = FindServer(map->name);
157       if(!acptr)
158       {
159         map_remove(map);
160         continue;
161       }
162       else
163         map_update(acptr);
164     }
165     send_reply(cptr, RPL_MAP, smap ? "|" : "`", "-", map->name, "", map->maxclients);
166   }
167 }
168
169 #endif /* HEAD_IN_SAND_MAP */
170
171 #ifdef HEAD_IN_SAND_LINKS
172 void map_dump_links_head_in_sand(struct Client *sptr, char *mask)
173 {
174   struct Map *link = 0;
175   struct Map *slink = 0;
176   struct Client *acptr = 0;
177
178   collapse(mask);
179   
180   for(link = MapList; link; link = slink)
181   {
182     slink = link->next;
183
184     if(link->lasttime < TStime() - MAP_CACHE_TIME)
185     {
186       acptr = FindServer(link->name);
187       if(!acptr)
188       {
189         map_remove(link);
190         continue;
191       }
192       else
193         map_update(acptr);
194     }
195     if (!BadPtr(mask) && match(mask, link->name))
196       continue;
197     send_reply(sptr, RPL_LINKS, link->name, cli_name(&me), 1, link->prot, 
198                link->info);
199   }
200   /* don't forget to send me */
201   send_reply(sptr, RPL_LINKS, cli_name(&me), cli_name(&me), 0, Protocol(&me),
202              cli_info(&me));
203 }
204 #endif /* HEAD_IN_SAND_LINKS */
205   
206 void map_dump(struct Client *cptr, struct Client *server, char *mask, int prompt_length)
207 {
208   static char prompt[64];
209   struct DLink *lp;
210   char *p = &prompt[prompt_length];
211   int cnt = 0;
212
213   *p = '\0';
214   if (prompt_length > 60)
215     send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server));
216   else {
217     char lag[512];
218     if (cli_serv(server)->lag>10000)
219         lag[0]=0;
220     else if (cli_serv(server)->lag<0)
221         strcpy(lag,"(0s)");
222     else
223         sprintf(lag,"(%is)",cli_serv(server)->lag);
224     send_reply(cptr, RPL_MAP, prompt, (
225                 (IsBurst(server)) ? "*" : (IsBurstAck(server) ? "!" : "")),
226                cli_name(server), lag, (server == &me) ? UserStats.local_clients :
227                cli_serv(server)->clients);
228   }
229   if (prompt_length > 0)
230   {
231     p[-1] = ' ';
232     if (p[-2] == '`')
233       p[-2] = ' ';
234   }
235   if (prompt_length > 60)
236     return;
237   strcpy(p, "|-");
238   for (lp = cli_serv(server)->down; lp; lp = lp->next)
239     if (match(mask, cli_name(lp->value.cptr)))
240       ClrFlag(lp->value.cptr, FLAG_MAP);
241     else
242     {
243       SetFlag(lp->value.cptr, FLAG_MAP);
244       cnt++;
245     }
246   for (lp = cli_serv(server)->down; lp; lp = lp->next)
247   {
248     if (!HasFlag(lp->value.cptr, FLAG_MAP))
249       continue;
250     if (--cnt == 0)
251       *p = '`';
252     map_dump(cptr, lp->value.cptr, mask, prompt_length + 2);
253   }
254   if (prompt_length > 0)
255     p[-1] = '-';
256 }
257
258