ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/servers.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (9 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 7808 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Routines to maintain a list of online servers.
2 * Based on code by Andrew Kempe (TheShadow)
3 * E-mail: <theshadow@shadowfire.org>
4 *
5 * IRC Services is copyright (c) 1996-2009 Andrew Church.
6 * E-mail: <achurch@achurch.org>
7 * Parts written by Andrew Kempe and others.
8 * This program is free but copyrighted software; see the file GPL.txt for
9 * details.
10 */
11
12 #include "services.h"
13 #include "modules.h"
14
15 /*************************************************************************/
16
17 #define add_server static add_server
18 #define del_server static del_server
19 #include "hash.h"
20 DEFINE_HASH(server, Server, name)
21 #undef add_server
22 #undef del_server
23
24 static Server *root_server; /* Entry for root server (Services) */
25 static int16 servercnt = 0; /* Number of online servers */
26
27 /* Callback IDs: */
28 static int cb_create = -1;
29 static int cb_delete = -1;
30
31 /*************************************************************************/
32 /**************************** Internal functions *************************/
33 /*************************************************************************/
34
35 /* Allocate a new Server structure, fill in basic values, link it to the
36 * overall list, and return it. Always successful.
37 */
38
39 static Server *new_server(const char *servername)
40 {
41 Server *server;
42
43 servercnt++;
44 server = scalloc(sizeof(Server), 1);
45 server->name = sstrdup(servername);
46 add_server(server);
47 return server;
48 }
49
50
51 /* Remove and free a Server structure. */
52
53 static void delete_server(Server *server)
54 {
55 del_server(server);
56 servercnt--;
57 free(server->name);
58 free(server);
59 }
60
61 /*************************************************************************/
62
63 /* Remove the given server. This takes care of recursively removing child
64 * servers, handling NOQUIT, calling the server delete callback, and
65 * actually deleting the server data.
66 */
67
68 static void recursive_squit(Server *parent, const char *reason);
69
70 static void squit_server(Server *server, const char *reason)
71 {
72 User *user, *nextuser;
73
74 recursive_squit(server, reason);
75 if (protocol_features & PF_NOQUIT) {
76 #define next snext
77 #define prev sprev
78 LIST_FOREACH_SAFE (user, server->userlist, nextuser)
79 quit_user(user, reason, 0);
80 #undef next
81 #undef prev
82 }
83 if (!server->fake)
84 call_callback_2(cb_delete, server, reason);
85 delete_server(server);
86 }
87
88
89 /* "SQUIT" all servers who are linked to us via the specified server by
90 * deleting them from the server list. The parent server is not deleted,
91 * so this must be done by the calling function.
92 */
93
94 static void recursive_squit(Server *parent, const char *reason)
95 {
96 Server *server, *nextserver;
97
98 server = parent->child;
99 log_debug(2, "recursive_squit, parent: %s", parent->name);
100 while (server) {
101 nextserver = server->sibling;
102 log_debug(2, "recursive_squit, child: %s", server->name);
103 squit_server(server, reason);
104 server = nextserver;
105 }
106 }
107
108 /*************************************************************************/
109 /**************************** External functions *************************/
110 /*************************************************************************/
111
112 /* Handle a server SERVER command.
113 * source = server's hub; an empty string indicates that this is our hub.
114 * av[0] = server's name
115 * If ac < 0, the server in av[0] is assumed to be a "dummy" server that
116 * should not be passed to the callback (e.g. for JUPE).
117 *
118 * When called internally to add a server (from OperServ JUPE, etc.),
119 * callers may assume that the contents of the argument strings will not be
120 * modified.
121 */
122
123 void do_server(const char *source, int ac, char **av)
124 {
125 Server *server, *tmpserver;
126
127 server = new_server(av[0]);
128 server->t_join = time(NULL);
129 server->child = NULL;
130 server->sibling = NULL;
131
132 if (source && *source) {
133 server->hub = get_server(source);
134 if (!server->hub) {
135 /* PARANOIA: This should NEVER EVER happen, but we check anyway.
136 *
137 * I've heard that on older ircds it is possible for "source"
138 * not to be the new server's hub. This will cause problems.
139 * -TheShadow
140 */
141 wallops(ServerName,
142 "WARNING: Could not find server \2%s\2 which is supposed "
143 "to be the hub for \2%s\2", source, av[0]);
144 log("server: could not find hub %s for %s", source, av[0]);
145 return;
146 }
147 } else {
148 server->hub = root_server;
149 }
150 if (!server->hub->child) {
151 server->hub->child = server;
152 } else {
153 tmpserver = server->hub->child;
154 while (tmpserver->sibling)
155 tmpserver = tmpserver->sibling;
156 tmpserver->sibling = server;
157 }
158
159 if (ac > 0)
160 call_callback_1(cb_create, server);
161 else
162 server->fake = 1;
163
164 return;
165 }
166
167 /*************************************************************************/
168
169 /* Handle a server SQUIT command.
170 * av[0] = server's name
171 * av[1] = quit message
172 */
173
174 void do_squit(const char *source, int ac, char **av)
175 {
176 Server *server;
177
178 server = get_server(av[0]);
179
180 if (server) {
181 if (server->hub) {
182 if (server->hub->child == server) {
183 server->hub->child = server->sibling;
184 } else {
185 Server *tmpserver;
186 for (tmpserver = server->hub->child; tmpserver->sibling;
187 tmpserver = tmpserver->sibling) {
188 if (tmpserver->sibling == server) {
189 tmpserver->sibling = server->sibling;
190 break;
191 }
192 }
193 }
194 }
195 squit_server(server, av[1]);
196
197 } else {
198 wallops(ServerName,
199 "WARNING: Tried to quit non-existent server: \2%s", av[0]);
200 log("server: Tried to quit non-existent server: %s", av[0]);
201 log("server: Input buffer: %s", inbuf);
202 return;
203 }
204 }
205
206 /*************************************************************************/
207 /*************************************************************************/
208
209 int server_init(int ac, char **av)
210 {
211 Server *server;
212
213 cb_create = register_callback("server create");
214 cb_delete = register_callback("server delete");
215 if (cb_create < 0 || cb_delete < 0) {
216 log("server_init: register_callback() failed\n");
217 return 0;
218 }
219 server = new_server("");
220 server->fake = 1;
221 server->t_join = time(NULL);
222 server->hub = server->child = server->sibling = NULL;
223 root_server = server;
224 return 1;
225 }
226
227 /*************************************************************************/
228
229 /* Remove all servers; this recursively takes out all users and channels,
230 * as well.
231 */
232
233 void server_cleanup(void)
234 {
235 uint32 pf = protocol_features;
236 protocol_features |= PF_NOQUIT;
237 squit_server(root_server, "server_cleanup");
238 protocol_features = pf;
239 unregister_callback(cb_delete);
240 unregister_callback(cb_create);
241 }
242
243 /*************************************************************************/
244
245 /* Return information on memory use. Assumes pointers are valid. */
246
247 void get_server_stats(long *nservers, long *memuse)
248 {
249 Server *server;
250 long mem;
251
252 mem = sizeof(Server) * servercnt;
253 for (server = first_server(); server; server = next_server())
254 mem += strlen(server->name)+1;
255
256 *nservers = servercnt;
257 *memuse = mem;
258 }
259
260 /*************************************************************************/
261
262 /*
263 * Local variables:
264 * c-file-style: "stroustrup"
265 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
266 * indent-tabs-mode: nil
267 * End:
268 *
269 * vim: expandtab shiftwidth=4:
270 */