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