1 /*
2
3 silcmap_html.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2003 - 2004 Pekka Riikonen
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; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include "silcincludes.h"
21 #include "silcclient.h"
22 #include "silcmap.h"
23
24 /* Write the HTML data file of the gathered data from the connection. */
25
26 bool silc_map_writehtml(SilcMap map, SilcMapConnection mapconn)
27 {
28 FILE *fp;
29 char *hostname;
30 char filename[256], line[128];
31 int begin;
32
33 /* Generate data filename. First configure hostname is the filename */
34 silc_dlist_start(mapconn->hostnames);
35 hostname = silc_dlist_get(mapconn->hostnames);
36 memset(filename, 0, sizeof(filename));
37 snprintf(filename, sizeof(filename) - 1, "%s_%d.html", hostname,
38 mapconn->port);
39
40 /* Open for writing */
41 fp = fopen(filename, "w+");
42 if (!fp) {
43 fprintf(stderr, "Could not open file '%s'\n", filename);
44 return FALSE;
45 }
46
47 /* Write the HTML page */
48
49 fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
50 fprintf(fp, "<br /><hr ><br />\n");
51
52 /* General stuff */
53
54 fprintf(fp, "<table cellspacing=\"\" cellpadding=\"\" border=\"\">\n");
55 silc_dlist_start(mapconn->hostnames);
56 while ((hostname = silc_dlist_get(mapconn->hostnames)) != SILC_LIST_END)
57 fprintf(fp, "<tr><td><b>Hostname</b></td><td> :</td><td> %s</td></tr>\n", hostname);
58
59 silc_dlist_start(mapconn->ips);
60 while ((hostname = silc_dlist_get(mapconn->ips)) != SILC_LIST_END)
61 fprintf(fp, "<tr><td><b>IP</b></td><td> :</td><td> %s</td></tr>\n", hostname);
62
63 fprintf(fp, "<tr><td><b>Port</b></td><td> :</td><td> %d</td></tr>\n", mapconn->port);
64 fprintf(fp, "<tr><td><b>Country</b></td><td> :</td><td> %s</td></tr>\n", mapconn->country);
65 fprintf(fp, "<tr><td><b>City</b></td><td> :</td><td> %s</td></tr>\n", mapconn->city);
66 fprintf(fp, "<tr><td><b>Admin</b></td><td> :</td><td> %s</td></tr>\n", mapconn->admin);
67 fprintf(fp, "</table>\n");
68
69 /* Public key */
70 if (mapconn->public_key) {
71 SilcPublicKey public_key;
72 SilcPublicKeyIdentifier ident;
73 char *fingerprint, *babbleprint;
74 unsigned char *pk;
75 SilcUInt32 pk_len;
76 SilcPKCS pkcs;
77 SilcUInt32 key_len = 0;
78 FILE *pd;
79 unsigned char *pdd;
80
81 fprintf(fp, " <br /><hr ><br />\n");
82 fprintf(fp, "<b>Public Key:</b> <br />\n");
83 fprintf(fp, "<table cellspacing=\"\" cellpadding=\"\" border=\"\">\n");
84
85 if (silc_pkcs_load_public_key(mapconn->public_key, &public_key,
86 SILC_PKCS_FILE_PEM) == FALSE)
87 if (silc_pkcs_load_public_key(mapconn->public_key, &public_key,
88 SILC_PKCS_FILE_BIN) == FALSE) {
89 fprintf(stderr, "Could not load public key file `%s'\n",
90 mapconn->public_key);
91 return FALSE;
92 }
93
94 ident = silc_pkcs_decode_identifier(public_key->identifier);
95 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
96 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
97 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
98
99 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
100 key_len = silc_pkcs_public_key_set(pkcs, public_key);
101 silc_pkcs_free(pkcs);
102 }
103
104 fprintf(fp, "<tr><td> ");
105 fprintf(fp, "Public key file</td><td> :</td><td> <a href=\"%s\">%s</a></td></tr>\n",
106 mapconn->public_key, mapconn->public_key);
107 fprintf(fp, "<tr><td> ");
108 fprintf(fp, "Algorithm</td><td> :</td><td> %s</td></tr>\n", public_key->name);
109 if (key_len) {
110 fprintf(fp, "<tr><td> ");
111 fprintf(fp, "Key length</td><td> :</td><td> %d bits</td></tr>\n", (unsigned int)key_len);
112 }
113 if (ident->realname) {
114 fprintf(fp, "<tr><td> ");
115 fprintf(fp, "Real name</td><td> :</td><td> %s</td></tr>\n", ident->realname);
116 }
117 if (ident->username) {
118 fprintf(fp, "<tr><td> ");
119 fprintf(fp, "Username</td><td> :</td><td> %s</td></tr>\n", ident->username);
120 }
121 if (ident->host) {
122 fprintf(fp, "<tr><td> ");
123 fprintf(fp, "Hostname</td><td> :</td><td> %s</td></tr>\n", ident->host);
124 }
125 if (ident->email) {
126 fprintf(fp, "<tr><td> ");
127 fprintf(fp, "Email</td><td> :</td><td> %s</td></tr>\n", ident->email);
128 }
129 if (ident->org) {
130 fprintf(fp, "<tr><td> ");
131 fprintf(fp, "Organization</td><td> :</td><td> %s</td></tr>\n", ident->org);
132 }
133 if (ident->country) {
134 fprintf(fp, "<tr><td> ");
135 fprintf(fp, "Country</td><td> :</td><td> %s</td></tr>\n", ident->country);
136 }
137 fprintf(fp, "<tr><td> ");
138 fprintf(fp, "Fingerprint</td><td> :</td><td> <tt>%s</tt></td></tr>\n", fingerprint);
139 fprintf(fp, "<tr><td> ");
140 fprintf(fp, "Babbleprint</td><td> :</td><td> <tt>%s</tt></td></tr>\n", babbleprint);
141 fprintf(fp, "</table>\n");
142
143 pd = fopen(mapconn->public_key, "r");
144 if (!pd)
145 return FALSE;
146
147 pk_len = silc_file_size(mapconn->public_key);
148 pdd = silc_calloc(pk_len + 2, sizeof(*pdd));
149 if (!pdd)
150 return FALSE;
151 fread(pdd, pk_len, 1, pd);
152 pdd[pk_len] = EOF;
153
154 fprintf(fp, "<br /><tt><small>\n");
155 begin = 0;
156 while (silc_gets(line, sizeof(line) - 1, pdd, pk_len + 1, &begin) != EOF)
157 fprintf(fp, "%s<br />\n", line);
158 fprintf(fp, "</small></tt><br />\n");
159
160 fclose(pd);
161 silc_free(pdd);
162 silc_free(fingerprint);
163 silc_free(babbleprint);
164 silc_free(pk);
165 silc_pkcs_public_key_free(public_key);
166 silc_pkcs_free_identifier(ident);
167 }
168
169 /* Description */
170 if (mapconn->description && mapconn->description[0]) {
171 fprintf(fp, "<hr ><br />\n");
172 fprintf(fp, "<b>Description:</b> <br />\n");
173 fprintf(fp, "%s<br /> <br />\n", mapconn->description);
174 }
175
176 /* Status */
177 if (mapconn->connect) {
178 fprintf(fp, "<hr ><br />\n");
179 fprintf(fp, "<b>Server status:</b> <br />\n");
180 if (mapconn->down)
181 fprintf(fp,
182 "Server is currently down and unreachable. "
183 "Please try again later to connect the server.<br />\n");
184 else
185 fprintf(fp,
186 "Server is up and running<br />\n");
187 }
188
189 if (mapconn->connect && !mapconn->down) {
190 int days, hours, mins, secs, uptime;
191
192 uptime = mapconn->data.uptime;
193 days = uptime / (24 * 60 * 60);
194 uptime -= days * (24 * 60 * 60);
195 hours = uptime / (60 * 60);
196 uptime -= hours * (60 * 60);
197 mins = uptime / 60;
198 uptime -= mins * 60;
199 secs = uptime;
200
201 /* Statistics */
202 fprintf(fp, "<br />\n");
203 fprintf(fp, "<b>Server statistics:</b> <br />\n");
204 fprintf(fp, "<table cellspacing=\"\" cellpadding=\"\" border=\"\">\n");
205 if (mapconn->starttime) {
206 fprintf(fp, "<tr><td> ");
207 fprintf(fp, "Server start time</td><td> :</td><td> %s<td></tr>\n",
208 silc_get_time(mapconn->data.starttime));
209 }
210 if (mapconn->uptime) {
211 fprintf(fp, "<tr><td> ");
212 fprintf(fp, "Server uptime</td><td> :</td><td> %d days %d hours %d mins %d secs<td></tr>\n",
213 days, hours, mins, secs);
214 }
215 if (mapconn->clients) {
216 fprintf(fp, "<tr><td> ");
217 fprintf(fp, "Local clients</td><td> :</td><td> %ld</td></tr>\n",
218 (unsigned long)mapconn->data.clients);
219 }
220 if (mapconn->channels) {
221 fprintf(fp, "<tr><td> ");
222 fprintf(fp, "Local channels</td><td> :</td><td> %ld</td></tr>\n",
223 (unsigned long)mapconn->data.channels);
224 }
225 if (mapconn->server_ops) {
226 fprintf(fp, "<tr><td> ");
227 fprintf(fp, "Local server operators</td><td> :</td><td> %ld</td></tr>\n",
228 (unsigned long)mapconn->data.server_ops);
229 }
230 if (mapconn->router_ops) {
231 fprintf(fp, "<tr><td> ");
232 fprintf(fp, "Local router operators</td><td> :</td><td> %ld</td></tr>\n",
233 (unsigned long)mapconn->data.router_ops);
234 }
235 if (mapconn->cell_clients) {
236 fprintf(fp, "<tr><td> ");
237 fprintf(fp, "Cell clients</td><td> :</td><td> %ld</td></tr>\n",
238 (unsigned long)mapconn->data.cell_clients);
239 }
240 if (mapconn->cell_channels) {
241 fprintf(fp, "<tr><td> ");
242 fprintf(fp, "Cell channels</td><td> :</td><td> %ld</td></tr>\n",
243 (unsigned long)mapconn->data.cell_channels);
244 }
245 if (mapconn->cell_servers) {
246 fprintf(fp, "<tr><td> ");
247 fprintf(fp, "Cell servers</td><td> :</td><td> %ld</td></tr>\n",
248 (unsigned long)mapconn->data.cell_servers);
249 }
250 if (mapconn->all_clients) {
251 fprintf(fp, "<tr><td> ");
252 fprintf(fp, "All SILC clients</td><td> :</td><td> %ld</td></tr>\n",
253 (unsigned long)mapconn->data.all_clients);
254 }
255 if (mapconn->all_channels) {
256 fprintf(fp, "<tr><td> ");
257 fprintf(fp, "All SILC channels</td><td> :</td><td> %ld</td></tr>\n",
258 (unsigned long)mapconn->data.all_channels);
259 }
260 if (mapconn->all_servers) {
261 fprintf(fp, "<tr><td> ");
262 fprintf(fp, "All SILC servers</td><td> :</td><td> %ld</td></tr>\n",
263 (unsigned long)mapconn->data.all_servers);
264 }
265 if (mapconn->all_routers) {
266 fprintf(fp, "<tr><td> ");
267 fprintf(fp, "All SILC routers</td><td> :</td><td> %ld</td></tr>\n",
268 (unsigned long)mapconn->data.all_routers);
269 }
270 if (mapconn->all_server_ops) {
271 fprintf(fp, "<tr><td> ");
272 fprintf(fp, "All SILC server operators</td><td> :</td><td> %ld</td></tr>\n",
273 (unsigned long)mapconn->data.all_server_ops);
274 }
275 if (mapconn->all_router_ops) {
276 fprintf(fp, "<tr><td> ");
277 fprintf(fp, "All SILC router operators</td><td> :</td><td> %ld</td></tr>\n",
278 (unsigned long)mapconn->data.all_router_ops);
279 }
280 fprintf(fp, "</table>\n");
281 }
282
283 /* motd */
284 if (mapconn->motd && mapconn->data.motd) {
285 fprintf(fp, " <br /><hr ><br />\n");
286 fprintf(fp, "<b>Message of the Day:</b> <br />\n");
287
288 fprintf(fp, "<br /><tt><small>\n");
289 begin = 0;
290 while (silc_gets(line, sizeof(line) - 1, mapconn->data.motd,
291 strlen(mapconn->data.motd), &begin) != EOF)
292 fprintf(fp, "%s<br />\n", line);
293 fprintf(fp, "</small></tt>\n");
294 }
295
296 fprintf(fp, "<br />\n");
297
298 fclose(fp);
299 return TRUE;
300 }
301
302 /* Write the HTML index file that lists all servers. */
303
304 bool silc_map_writehtml_index(SilcMap map)
305 {
306 SilcMapConnection mapconn;
307 char *hostname, *ip, *class;
308 FILE *fp;
309
310 /* Open for writing */
311 fp = fopen(map->writehtml.filename, "w+");
312 if (!fp) {
313 fprintf(stderr, "Could not open file '%s'\n", map->writehtml.filename);
314 return FALSE;
315 }
316
317 /* Produce a simple HTML index file of all servers */
318 class = map->writehtml.text ? map->writehtml.text : "silcmap";
319
320 fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
321 fprintf(fp, "<br />\n");
322 fprintf(fp, "<table cellspacing=\"\" cellpadding=\"\" "
323 "class=\"%s\" border=\"\">\n", class);
324 fprintf(fp,
325 "<tr>\n"
326 "<td align=\"center\" class=\"%s_header\"><b>Hostname</b></td>\n"
327 "<td align=\"center\" class=\"%s_header\"><b>IPv4 Address</b></td>\n"
328 "<td align=\"center\" class=\"%s_header\"><b>Port</b></td>\n"
329 "<td align=\"center\" class=\"%s_header\"><b>Country</b></td>\n"
330 "<td align=\"center\" class=\"%s_header\"><b>Oper</b></td>\n"
331 "</tr>\n", class, class, class, class, class);
332
333 silc_dlist_start(map->conns);
334 while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
335
336 silc_dlist_start(mapconn->hostnames);
337 hostname = silc_dlist_get(mapconn->hostnames);
338 silc_dlist_start(mapconn->ips);
339 ip = silc_dlist_get(mapconn->ips);
340
341 fprintf(fp, "<tr>\n");
342 if (mapconn->html_url)
343 fprintf(fp,
344 "<td align = \"center\" class=\"%s\"> <a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
345 else
346 fprintf(fp,
347 "<td align = \"center\" class=\"%s\"> <a href=\"%s_%d.html\">%s</a></td>\n", class, hostname, mapconn->port, hostname);
348 fprintf(fp,
349 "<td align = \"center\" class=\"%s\"> %s</td>\n"
350 "<td align = \"center\" class=\"%s\"> %d</td>\n"
351 "<td align = \"center\" class=\"%s\"> %s</td>\n"
352 "<td align = \"center\" class=\"%s\"> %s</td>\n"
353 "</tr>\n",
354 class, ip, class, mapconn->port, class,
355 mapconn->country, class, mapconn->admin);
356 }
357
358 fprintf(fp, "</table><br />\n");
359
360 return TRUE;
361 }
362
363 /* Creates a HTML map file, which can be used to allow user to click
364 URLs on the image at the specified locations. */
365
366 bool silc_map_writemaphtml(SilcMap map)
367 {
368 SilcMapConnection mapconn;
369 SilcMapCommand cmd, c;
370 char *hostname, url[256];
371 FILE *fp;
372 int i, xx , yy, w, h;
373
374 for (i = 0; i < map->writemaphtml_count; i++) {
375 c = &map->writemaphtml[i];
376 if (c->alon && c->alat) {
377 c->x = silc_map_lon2x(map, c->alon);
378 c->y = silc_map_lat2y(map, c->alat);
379 }
380
381 /* Open for writing */
382 fp = fopen(c->filename, "w+");
383 if (!fp) {
384 fprintf(stderr, "Could not open file '%s'\n", c->filename);
385 return FALSE;
386 }
387
388 /* The target may be portion of the original map, so we must make the
389 new coordinates relative to the new map. */
390 xx = c->x;
391 yy = c->y;
392
393 memset(url, 0, sizeof(url));
394
395 fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
396 fprintf(fp, "<img src=\"%s\" usemap=\"#map\" class=\"silcmap\">\n",
397 c->text);
398 fprintf(fp, "<map name=\"map\">\n");
399
400 silc_dlist_start(map->conns);
401 while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
402 memset(url, 0, sizeof(url));
403 if (mapconn->html_url && mapconn->html_url[0]) {
404 silc_strncat(url, sizeof(url), mapconn->html_url,
405 strlen(mapconn->html_url));
406 } else {
407 silc_dlist_start(mapconn->hostnames);
408 hostname = silc_dlist_get(mapconn->hostnames);
409 snprintf(url, sizeof(url) - 1, "%s_%d.html", hostname, mapconn->port);
410 }
411
412 /* Print the positions of various items on the map into the map file */
413 silc_dlist_start(mapconn->commands);
414 while ((cmd = silc_dlist_get(mapconn->commands)) != SILC_LIST_END) {
415 if (cmd->alon && cmd->alat) {
416 cmd->x = silc_map_lon2x(map, cmd->alon);
417 cmd->y = silc_map_lat2y(map, cmd->alat);
418 }
419
420 if (cmd->draw_text) {
421 w = strlen(cmd->text) * 5;
422 h = map->font.height - 2;
423 fprintf(fp,
424 "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
425 (int)(cmd->x - xx), (int)(cmd->y - yy), w, h, url);
426 }
427
428 if (cmd->draw_circle) {
429 w = 4;
430 fprintf(fp,
431 "<area shape=\"circle\" coords=\"%d,%d,%d\" href=\"%s\">\n",
432 (int)(cmd->x - xx), (int)(cmd->y - yy), w, url);
433 if (cmd->text) {
434 w = strlen(cmd->text) * 5;
435 h = map->font.height - 2;
436 fprintf(fp,
437 "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
438 (int)(cmd->x - xx + cmd->lposx),
439 (int)(cmd->y - yy - cmd->lposy),
440 (int)(cmd->x - xx + cmd->lposx + w),
441 (int)(cmd->y - yy - cmd->lposy + h), url);
442 }
443 }
444
445 if (cmd->draw_rectangle) {
446 w = 7;
447 h = 6;
448 fprintf(fp,
449 "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
450 (int)(cmd->x - xx), (int)(cmd->y - yy),
451 (int)(cmd->x - xx + w), (int)(cmd->y - yy + h), url);
452 if (cmd->text) {
453 w = strlen(cmd->text) * 5;
454 h = map->font.height - 2;
455 fprintf(fp,
456 "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
457 (int)(cmd->x - xx + cmd->lposx),
458 (int)(cmd->y - yy - cmd->lposy),
459 (int)(cmd->x - xx + cmd->lposx + w),
460 (int)(cmd->y - yy - cmd->lposy + h), url);
461 }
462 }
463 }
464 }
465
466 fprintf(fp, "</map>\n");
467 fclose(fp);
468 }
469
470 return TRUE;
471 }
472
473 /* Writes the server uptime reliablity data file. */
474
475 bool silc_map_writerel(SilcMap map, SilcMapConnection mapconn)
476 {
477 FILE *fp;
478 int try = 0, success = 0;
479 char f[256], *hostname;
480
481 /* Generate data filename */
482 memset(f, 0, sizeof(f));
483 silc_dlist_start(mapconn->hostnames);
484 hostname = silc_dlist_get(mapconn->hostnames);
485 snprintf(f, sizeof(f) - 1, "%s_%d.rel", hostname, mapconn->port);
486
487 /* Read the current data */
488 fp = fopen(f, "r");
489 if (fp) {
490 fscanf(fp, "%d:%d", &try, &success);
491 fclose(fp);
492 }
493
494 /* Update the data */
495 try++;
496 success = (mapconn->down == FALSE ? success + 1 : success);
497
498 /* Write the data file */
499 fp = fopen(f, "w+");
500 if (!fp) {
501 fprintf(stderr, "Could not open file '%s'\n", map->writerel.filename);
502 return FALSE;
503 }
504 fprintf(fp, "%d:%d", try, success);
505
506 fclose(fp);
507 return TRUE;
508 }
509
510 /* Writes the servers' uptime reliability graph as HTML page. */
511
512 bool silc_map_writerelhtml(SilcMap map)
513 {
514 SilcMapConnection mapconn;
515 char *hostname, *class;
516 FILE *fp, *dp;
517
518 /* Open for writing */
519 fp = fopen(map->writerel.filename, "w+");
520 if (!fp) {
521 fprintf(stderr, "Could not open file '%s'\n", map->writerel.filename);
522 return FALSE;
523 }
524
525 /* Produce the reliability graph as HTML file. */
526 class = map->writerel.text ? map->writerel.text : "silcmap";
527
528 fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
529 fprintf(fp, "<br />\n");
530 fprintf(fp, "<table cellspacing=\"\" cellpadding=\"\" "
531 "class=\"%s\" border=\"\">\n", class);
532 fprintf(fp,
533 "<tr>\n"
534 "<td align=\"center\" class=\"%s_header\"><b>Server</b></td>\n"
535 "<td colspan=\"2\" align=\"center\" class=\"%s_header\"><b>Reliability</b></td>\n"
536 "</tr>\n", class, class);
537
538 silc_dlist_start(map->conns);
539 while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
540 char f[256];
541 int try = 0, success = 0;
542 double rel = 0;
543
544 silc_dlist_start(mapconn->hostnames);
545 hostname = silc_dlist_get(mapconn->hostnames);
546
547 /* Get the data */
548 memset(f, 0, sizeof(f));
549 snprintf(f, sizeof(f) - 1, "%s_%d.rel", hostname, mapconn->port);
550 dp = fopen(f, "r");
551 if (dp) {
552 fscanf(dp, "%d:%d", &try, &success);
553 fclose(dp);
554 }
555
556 /* Count the reliability */
557 if (try)
558 rel = ((double)success / (double)try) * (double)160.0;
559
560 fprintf(fp, "<tr>\n");
561 if (mapconn->html_url)
562 fprintf(fp,
563 "<td align = \"center\" class=\"%s\"> <a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
564 else
565 fprintf(fp,
566 "<td align = \"center\" class=\"%s\"> <a href=\"%s_%d.html\">%s</a></td>\n", class, hostname, mapconn->port, hostname);
567 fprintf(fp,
568 "<td class=\"%s\" width=\"160\">"
569 "<table style=\"border: solid 1px black; width: 160px;\" border=\"\" cellpadding=\"\" cellspacing=\"\" class=\"%s\"><tr>"
570 "<td style=\"width: %fpx; height: 10px;\" bgcolor=\"gray\"></td>"
571 "<td style=\"width: %fpx; height: 10px;\" bgcolor=\"white\"></td>"
572 "</tr></table></td>\n"
573 "<td class=\"%s\">%.2f%% - score: %d</td>\n"
574 "</tr>\n",
575 class, class, rel, 160 - rel, class,
576 ((double)success / (double)try) * (double)100.0, success);
577 }
578
579 fprintf(fp, "</table><br />\n");
580
581 return TRUE;
582 }
583
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse