aef23d9fe973a4a15282f18ccd496a77115b5d65
[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 (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>&nbsp;<br />\n");
173     fprintf(fp, "%s<br />&nbsp;<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>&nbsp;<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>&nbsp;<br />\n");
204     fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n");
205     if (mapconn->starttime) {
206       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
207       fprintf(fp, "Server start time</td><td>&nbsp;:</td><td>&nbsp;%s<td></tr>\n",
208               silc_get_time(mapconn->data.starttime));
209     }
210     if (mapconn->uptime) {
211       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
212       fprintf(fp, "Server uptime</td><td>&nbsp;:</td><td>&nbsp;%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>&nbsp;&nbsp;");
217       fprintf(fp, "Local clients</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
218               (unsigned long)mapconn->data.clients);
219     }
220     if (mapconn->channels) {
221       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
222       fprintf(fp, "Local channels</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
223               (unsigned long)mapconn->data.channels);
224     }
225     if (mapconn->server_ops) {
226       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
227       fprintf(fp, "Local server operators</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
228               (unsigned long)mapconn->data.server_ops);
229     }
230     if (mapconn->router_ops) {
231       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
232       fprintf(fp, "Local router operators</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
233               (unsigned long)mapconn->data.router_ops);
234     }
235     if (mapconn->cell_clients) {
236       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
237       fprintf(fp, "Cell clients</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
238               (unsigned long)mapconn->data.cell_clients);
239     }
240     if (mapconn->cell_channels) {
241       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
242       fprintf(fp, "Cell channels</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
243               (unsigned long)mapconn->data.cell_channels);
244     }
245     if (mapconn->cell_servers) {
246       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
247       fprintf(fp, "Cell servers</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
248               (unsigned long)mapconn->data.cell_servers);
249     }
250     if (mapconn->all_clients) {
251       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
252       fprintf(fp, "All SILC clients</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
253               (unsigned long)mapconn->data.all_clients);
254     }
255     if (mapconn->all_channels) {
256       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
257       fprintf(fp, "All SILC channels</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
258               (unsigned long)mapconn->data.all_channels);
259     }
260     if (mapconn->all_servers) {
261       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
262       fprintf(fp, "All SILC servers</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
263               (unsigned long)mapconn->data.all_servers);
264     }
265     if (mapconn->all_routers) {
266       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
267       fprintf(fp, "All SILC routers</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
268               (unsigned long)mapconn->data.all_routers);
269     }
270     if (mapconn->all_server_ops) {
271       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
272       fprintf(fp, "All SILC server operators</td><td>&nbsp;:</td><td>&nbsp;%ld</td></tr>\n",
273               (unsigned long)mapconn->data.all_server_ops);
274     }
275     if (mapconn->all_router_ops) {
276       fprintf(fp, "<tr><td>&nbsp;&nbsp;");
277       fprintf(fp, "All SILC router operators</td><td>&nbsp;:</td><td>&nbsp;%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, "&nbsp;<br /><hr ><br />\n");
286     fprintf(fp, "<b>Message of the Day:</b>&nbsp;<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=\"0\" cellpadding=\"0\" "
323           "class=\"%s\" border=\"0\">\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\">&nbsp;<a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
345     else
346       fprintf(fp,
347               "<td align = \"center\" class=\"%s\">&nbsp;<a href=\"%s_%d.html\">%s</a></td>\n", class, hostname, mapconn->port, hostname);
348     fprintf(fp,
349             "<td align = \"center\" class=\"%s\">&nbsp;%s</td>\n"
350             "<td align = \"center\" class=\"%s\">&nbsp;%d</td>\n"
351             "<td align = \"center\" class=\"%s\">&nbsp;%s</td>\n"
352             "<td align = \"center\" class=\"%s\">&nbsp;%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=\"0\" cellpadding=\"0\" "
531           "class=\"%s\" border=\"0\">\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\">&nbsp;<a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
564     else
565       fprintf(fp,
566               "<td align = \"center\" class=\"%s\">&nbsp;<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=\"0\" cellpadding=\"0\" cellspacing=\"0\" 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 }