Debugs
[crypto.git] / apps / silcmap / silcmap_client.c
1 /*
2
3   silcmap_client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2003 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 /******* Map Client Routines *************************************************/
25
26 SILC_TASK_CALLBACK(silc_map_process_done)
27 {
28   SilcMap map = context;
29
30   /* Program stops */
31   silc_schedule_stop(map->client->schedule);
32 }
33
34 /* This function processes the data that was gathered from the server
35    and producess the outputs and the map. */
36
37 void silc_map_process_data(SilcMap map, SilcMapConnection mapconn)
38 {
39   SilcMapCommand cmd;
40   SilcMap ret_map;
41   SilcInt16 r, g, b, lr, lg, lb;
42   int i;
43
44   map->conn_num++;
45   SILC_LOG_DEBUG(("Processing the data from server (%d/%d)",
46                   map->conn_num, map->conns_num));
47
48   /* Change colors according to server status */
49   silc_map_parse_color(mapconn->up_color, &r, &g, &b);
50   silc_map_parse_color(mapconn->up_text_color, &lr, &lg, &lb);
51   if (mapconn->down) {
52     silc_map_parse_color(mapconn->down_color, &r, &g, &b);
53     silc_map_parse_color(mapconn->down_text_color, &lr, &lg, &lb);
54   }
55
56   /* Execute the map commands */
57   silc_dlist_start(mapconn->commands);
58   while ((cmd = silc_dlist_get(mapconn->commands)) != SILC_LIST_END) {
59     if (cmd->cut) {
60       if (silc_map_cut(map, cmd->x, cmd->y, cmd->width,
61                        cmd->height, &ret_map)) {
62         silc_map_write_ppm(ret_map, cmd->filename);
63         silc_map_free(ret_map);
64       }
65       continue;
66     }
67
68     if (cmd->draw_line) {
69       if (cmd->color_set) {
70         r = cmd->r;
71         g = cmd->g;
72         b = cmd->b;
73       }
74       silc_map_draw_line(map, cmd->width, cmd->x, cmd->y, cmd->x2, cmd->y2,
75                          r, g, b);
76       continue;
77     }
78
79     if (cmd->draw_text) {
80       if (cmd->color_set) {
81         lr = cmd->r;
82         lg = cmd->g;
83         lb = cmd->b;
84       }
85       silc_map_draw_text(map, cmd->text, cmd->x, cmd->y, lr, lg, lb);
86
87       continue;
88     }
89
90     if (cmd->draw_circle) {
91       if (cmd->color_set) {
92         r = cmd->r;
93         g = cmd->g;
94         b = cmd->b;
95       }
96       if (cmd->lcolor_set) {
97         lr = cmd->lr;
98         lg = cmd->lg;
99         lb = cmd->lb;
100       }
101       silc_map_draw_circle(map, cmd->x, cmd->y, r, g, b,
102                            cmd->text, cmd->lposx, cmd->lposy, lr, lg, lb);
103       continue;
104     }
105
106     if (cmd->draw_rectangle) {
107       if (cmd->color_set) {
108         r = cmd->r;
109         g = cmd->g;
110         b = cmd->b;
111       }
112       if (cmd->lcolor_set) {
113         lr = cmd->lr;
114         lg = cmd->lg;
115         lb = cmd->lb;
116       }
117       silc_map_draw_rectangle(map, cmd->x, cmd->y, r, g, b,
118                               cmd->text, cmd->lposx, cmd->lposy, lr, lg, lb);
119       continue;
120     }
121
122   }
123
124   /* Write the html data file */
125   if (map->writehtml.writehtml)
126     silc_map_writehtml(map, mapconn);
127
128   /* If this was last connection, we are done and ready to quit. */
129   if (map->conn_num == map->conns_num) {
130     SILC_LOG_DEBUG(("All connections processed"));
131
132     /* Produce output */
133     if (map->writemap.writemap)
134       silc_map_write_ppm(map, map->writemap.filename);
135     for (i = 0; i < map->cut_count; i++) {
136       if (silc_map_cut(map, map->cut[i].x, map->cut[i].y, map->cut[i].width,
137                        map->cut[i].height, &ret_map)) {
138         silc_map_write_ppm(ret_map, map->cut[i].filename);
139         silc_map_free(ret_map);
140       }
141     }
142
143     /* Write the HTML index file */
144     if (map->writehtml.writehtml)
145       silc_map_writehtml_index(map);
146
147     /* Write the HTML map file(s) */
148     silc_map_writemaphtml(map);
149
150     /* Schedule to stop */
151     silc_schedule_task_add(map->client->schedule, 0,
152                            silc_map_process_done, map, 0, 1,
153                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
154   }
155 }
156
157 /* Timeout callback to detect if server is down. */
158
159 SILC_TASK_CALLBACK(silc_map_connect_timeout)
160 {
161   SilcMapConnection mapconn = context;
162
163   SILC_LOG_DEBUG(("Connection timeout"));
164
165   /* The server is down. */
166   mapconn->down = TRUE;
167
168   /* Continue to produce the data and the map. */
169   silc_map_process_data(mapconn->map, mapconn);
170 }
171
172 /* Close connection to server */
173
174 SILC_TASK_CALLBACK(silc_map_connect_close)
175 {
176   SilcMapConnection mapconn = context;
177
178   SILC_LOG_DEBUG(("Closing connection to %s:%d", mapconn->conn->remote_host,
179                   mapconn->conn->remote_port));
180
181   silc_client_close_connection(mapconn->conn->client, mapconn->conn);
182
183   /* Continue to produce the data and the map. */
184   silc_map_process_data(mapconn->map, mapconn);
185 }
186
187 /* Create connection to remote server to gather information about it. */
188
189 void silc_map_connect(SilcMap map, SilcMapConnection mapconn)
190 {
191   char *ip;
192
193   if (!mapconn->connect) {
194     silc_schedule_task_add(map->client->schedule, 0,
195                            silc_map_connect_timeout, mapconn, 0, 1,
196                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
197     return;
198   }
199
200   /* First configure IP is used to connect. */
201   silc_dlist_start(mapconn->ips);
202   ip = silc_dlist_get(mapconn->ips);
203
204   SILC_LOG_DEBUG(("Creating connection to server %s:%d", ip, mapconn->port));
205
206   /* Create connection.  We'll continue in the silc_connected after
207      connection is created. */
208   silc_client_connect_to_server(map->client, NULL,
209                                 mapconn->port, ip, mapconn);
210
211   /* Set connect timeout to detect if the server is down. */
212   silc_schedule_task_add(map->client->schedule, 0,
213                          silc_map_connect_timeout, mapconn,
214                          mapconn->connect_timeout, 0,
215                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
216 }
217
218
219 /******* SILC Client Operations **********************************************/
220
221 /* "say" client operation is a message from the client library to the
222    application.  It may include error messages or something else.  We
223    just dump them to screen. */
224
225 static void
226 silc_say(SilcClient client, SilcClientConnection conn,
227          SilcClientMessageType type, char *msg, ...)
228 {
229
230 }
231
232
233 /* Message for a channel. The `sender' is the sender of the message
234    The `channel' is the channel. The `message' is the message.  Note
235    that `message' maybe NULL.  The `flags' indicates message flags
236    and it is used to determine how the message can be interpreted
237    (like it may tell the message is multimedia message). */
238
239 static void
240 silc_channel_message(SilcClient client, SilcClientConnection conn,
241                      SilcClientEntry sender, SilcChannelEntry channel,
242                      SilcMessagePayload payload,
243                      SilcMessageFlags flags, const unsigned char *message,
244                      SilcUInt32 message_len)
245 {
246
247 }
248
249
250 /* Private message to the client. The `sender' is the sender of the
251    message. The message is `message'and maybe NULL.  The `flags'
252    indicates message flags  and it is used to determine how the message
253    can be interpreted (like it may tell the message is multimedia
254    message). */
255
256 static void
257 silc_private_message(SilcClient client, SilcClientConnection conn,
258                      SilcClientEntry sender, SilcMessagePayload payload,
259                      SilcMessageFlags flags,
260                      const unsigned char *message,
261                      SilcUInt32 message_len)
262 {
263
264 }
265
266
267 /* Notify message to the client. The notify arguments are sent in the
268    same order as servers sends them. The arguments are same as received
269    from the server except for ID's.  If ID is received application receives
270    the corresponding entry to the ID. For example, if Client ID is received
271    application receives SilcClientEntry.  Also, if the notify type is
272    for channel the channel entry is sent to application (even if server
273    does not send it because client library gets the channel entry from
274    the Channel ID in the packet's header). */
275
276 static void
277 silc_notify(SilcClient client, SilcClientConnection conn,
278             SilcNotifyType type, ...)
279 {
280
281 }
282
283
284 /* Command handler. This function is called always in the command function.
285    If error occurs it will be called as well. `conn' is the associated
286    client connection. `cmd_context' is the command context that was
287    originally sent to the command. `success' is FALSE if error occurred
288    during command. `command' is the command being processed. It must be
289    noted that this is not reply from server. This is merely called just
290    after application has called the command. Just to tell application
291    that the command really was processed. */
292
293 static void
294 silc_command(SilcClient client, SilcClientConnection conn,
295              SilcClientCommandContext cmd_context, bool success,
296              SilcCommand command, SilcStatus status)
297 {
298
299 }
300
301
302 /* Command reply handler. This function is called always in the command reply
303    function. If error occurs it will be called as well. Normal scenario
304    is that it will be called after the received command data has been parsed
305    and processed. The function is used to pass the received command data to
306    the application.
307
308    `conn' is the associated client connection. `cmd_payload' is the command
309    payload data received from server and it can be ignored. It is provided
310    if the application would like to re-parse the received command data,
311    however, it must be noted that the data is parsed already by the library
312    thus the payload can be ignored. `success' is FALSE if error occurred.
313    In this case arguments are not sent to the application. The `status' is
314    the command reply status server returned. The `command' is the command
315    reply being processed. The function has variable argument list and each
316    command defines the number and type of arguments it passes to the
317    application (on error they are not sent). */
318
319 static void
320 silc_command_reply(SilcClient client, SilcClientConnection conn,
321                    SilcCommandPayload cmd_payload, bool success,
322                    SilcCommand command, SilcStatus status, ...)
323 {
324   SilcMapConnection mapconn = conn->context;
325   va_list va;
326
327   /* If error occurred in client library with our command, print the error */
328   if (status != SILC_STATUS_OK)
329     fprintf(stderr, "COMMAND REPLY %s: %s\n",
330             silc_get_command_name(command),
331             silc_get_status_message(status));
332
333   if (!success)
334     return;
335
336   va_start(va, status);
337
338   switch (command) {
339   case SILC_COMMAND_STATS:
340     {
341       unsigned char *stats = va_arg(va, unsigned char *);
342       SilcUInt32 stats_len = va_arg(va, SilcUInt32);
343       SilcBufferStruct buf;
344
345       SILC_LOG_DEBUG(("STATS command reply"));
346
347       /* Get statistics structure */
348       silc_buffer_set(&buf, stats, stats_len);
349       silc_buffer_unformat(&buf,
350                            SILC_STR_UI_INT(&mapconn->data.starttime),
351                            SILC_STR_UI_INT(&mapconn->data.uptime),
352                            SILC_STR_UI_INT(&mapconn->data.clients),
353                            SILC_STR_UI_INT(&mapconn->data.channels),
354                            SILC_STR_UI_INT(&mapconn->data.server_ops),
355                            SILC_STR_UI_INT(&mapconn->data.router_ops),
356                            SILC_STR_UI_INT(&mapconn->data.cell_clients),
357                            SILC_STR_UI_INT(&mapconn->data.cell_channels),
358                            SILC_STR_UI_INT(&mapconn->data.cell_servers),
359                            SILC_STR_UI_INT(&mapconn->data.all_clients),
360                            SILC_STR_UI_INT(&mapconn->data.all_channels),
361                            SILC_STR_UI_INT(&mapconn->data.all_servers),
362                            SILC_STR_UI_INT(&mapconn->data.all_routers),
363                            SILC_STR_UI_INT(&mapconn->data.all_server_ops),
364                            SILC_STR_UI_INT(&mapconn->data.all_router_ops),
365                            SILC_STR_END);
366
367       mapconn->stats_received = TRUE;
368     }
369     break;
370
371   case SILC_COMMAND_MOTD:
372     {
373       char *motd = va_arg(va, char *);
374
375       SILC_LOG_DEBUG(("MOTD command reply"));
376
377       mapconn->data.motd = strdup(motd);
378       mapconn->motd_received = TRUE;
379     }
380     break;
381
382   default:
383     break;
384   };
385
386   va_end(va);
387
388   if (mapconn->motd && !mapconn->motd_received)
389     return;
390   if (!mapconn->stats_received)
391     return;
392
393   /* All data is gathered, time to disconnect from the server. */
394   silc_schedule_task_add(client->schedule, 0,
395                          silc_map_connect_close, mapconn, 0, 1,
396                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
397 }
398
399
400 /* Called to indicate that connection was either successfully established
401    or connecting failed.  This is also the first time application receives
402    the SilcClientConnection objecet which it should save somewhere.
403    If the `success' is FALSE the application must always call the function
404    silc_client_close_connection. */
405
406 static void
407 silc_connected(SilcClient client, SilcClientConnection conn,
408                SilcClientConnectionStatus status)
409 {
410   SilcMapConnection mapconn = conn->context;
411   SilcMap map = mapconn->map;
412
413   silc_schedule_task_del_by_context(client->schedule, mapconn);
414
415   if (status == SILC_CLIENT_CONN_ERROR) {
416     fprintf(stderr, "Could not connect to server\n");
417     silc_client_close_connection(client, conn);
418
419     /* Mark that this server is down. */
420     silc_schedule_task_add(map->client->schedule, 0,
421                            silc_map_connect_timeout, mapconn, 0, 1,
422                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
423     return;
424   }
425
426   if (mapconn->down) {
427     /* Already timeouted */
428     SILC_LOG_DEBUG(("Connection already timedout"));
429     silc_client_close_connection(client, conn);
430     return;
431   }
432
433   SILC_LOG_DEBUG(("Connected to server %s:%d", conn->remote_host,
434                   conn->remote_port));
435
436   mapconn->conn = conn;
437
438   /* Get statistics */
439   silc_client_command_call(client, conn, "STATS");
440
441   /* Get motd if requested */
442   if (mapconn->motd) {
443     char motd[256];
444     char *hostname;
445     silc_dlist_start(mapconn->hostnames);
446     hostname = silc_dlist_get(mapconn->hostnames);
447     memset(motd, 0, sizeof(motd));
448     silc_strncat(motd, sizeof(motd), "MOTD ", 5);
449     silc_strncat(motd, sizeof(motd), hostname, strlen(hostname));
450     silc_client_command_call(client, conn, motd);
451   }
452 }
453
454
455 /* Called to indicate that connection was disconnected to the server.
456    The `status' may tell the reason of the disconnection, and if the
457    `message' is non-NULL it may include the disconnection message
458    received from server. */
459
460 static void
461 silc_disconnected(SilcClient client, SilcClientConnection conn,
462                   SilcStatus status, const char *message)
463 {
464   SilcMapConnection mapconn = conn->context;
465
466   silc_schedule_task_del_by_context(client->schedule, mapconn);
467
468   SILC_LOG_DEBUG(("Disconnected from server %s:%d", conn->remote_host,
469                   conn->remote_port));
470
471   mapconn->conn = NULL;
472 }
473
474
475 /* Find authentication method and authentication data by hostname and
476    port. The hostname may be IP address as well. When the authentication
477    method has been resolved the `completion' callback with the found
478    authentication method and authentication data is called. The `conn'
479    may be NULL. */
480
481 static void
482 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
483                      char *hostname, SilcUInt16 port,
484                      SilcGetAuthMeth completion,
485                      void *context)
486 {
487   /* No auth */
488   completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
489 }
490
491
492 /* Verifies received public key. The `conn_type' indicates which entity
493    (server, client etc.) has sent the public key. If user decides to trust
494    the application may save the key as trusted public key for later
495    use. The `completion' must be called after the public key has been
496    verified. */
497
498 static void
499 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
500                        SilcSocketType conn_type, unsigned char *pk,
501                        SilcUInt32 pk_len, SilcSKEPKType pk_type,
502                        SilcVerifyPublicKey completion, void *context)
503 {
504   /* Accept all keys without verification */
505   completion(TRUE, context);
506 }
507
508
509 /* Ask (interact, that is) a passphrase from user. The passphrase is
510    returned to the library by calling the `completion' callback with
511    the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
512    if not then the library will attempt to encode. */
513
514 static void
515 silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
516                     SilcAskPassphrase completion, void *context)
517 {
518   completion(NULL, 0, context);
519 }
520
521
522 /* Notifies application that failure packet was received.  This is called
523    if there is some protocol active in the client.  The `protocol' is the
524    protocol context.  The `failure' is opaque pointer to the failure
525    indication.  Note, that the `failure' is protocol dependant and
526    application must explicitly cast it to correct type.  Usually `failure'
527    is 32 bit failure type (see protocol specs for all protocol failure
528    types). */
529
530 static void
531 silc_failure(SilcClient client, SilcClientConnection conn,
532              SilcProtocol protocol, void *failure)
533 {
534   fprintf(stderr, "Connecting failed (protocol failure)\n");
535 }
536
537
538 /* Asks whether the user would like to perform the key agreement protocol.
539    This is called after we have received an key agreement packet or an
540    reply to our key agreement packet. This returns TRUE if the user wants
541    the library to perform the key agreement protocol and FALSE if it is not
542    desired (application may start it later by calling the function
543    silc_client_perform_key_agreement). If TRUE is returned also the
544    `completion' and `context' arguments must be set by the application. */
545
546 static bool
547 silc_key_agreement(SilcClient client, SilcClientConnection conn,
548                    SilcClientEntry client_entry, const char *hostname,
549                    SilcUInt16 port, SilcKeyAgreementCallback *completion,
550                    void **context)
551 {
552   return FALSE;
553 }
554
555
556 /* Notifies application that file transfer protocol session is being
557    requested by the remote client indicated by the `client_entry' from
558    the `hostname' and `port'. The `session_id' is the file transfer
559    session and it can be used to either accept or reject the file
560    transfer request, by calling the silc_client_file_receive or
561    silc_client_file_close, respectively. */
562
563 static void
564 silc_ftp(SilcClient client, SilcClientConnection conn,
565          SilcClientEntry client_entry, SilcUInt32 session_id,
566          const char *hostname, SilcUInt16 port)
567 {
568
569 }
570
571
572 /* Delivers SILC session detachment data indicated by `detach_data' to the
573    application.  If application has issued SILC_COMMAND_DETACH command
574    the client session in the SILC network is not quit.  The client remains
575    in the network but is detached.  The detachment data may be used later
576    to resume the session in the SILC Network.  The appliation is
577    responsible of saving the `detach_data', to for example in a file.
578
579    The detachment data can be given as argument to the functions
580    silc_client_connect_to_server, or silc_client_add_connection when
581    creating connection to remote server, inside SilcClientConnectionParams
582    structure.  If it is provided the client library will attempt to resume
583    the session in the network.  After the connection is created
584    successfully, the application is responsible of setting the user
585    interface for user into the same state it was before detaching (showing
586    same channels, channel modes, etc).  It can do this by fetching the
587    information (like joined channels) from the client library. */
588
589 static void
590 silc_detach(SilcClient client, SilcClientConnection conn,
591             const unsigned char *detach_data, SilcUInt32 detach_data_len)
592 {
593
594 }
595
596 /* This structure and all the functions were taken from the
597    lib/silcclient/client_ops_example.c. */
598 SilcClientOperations silc_map_client_ops = {
599   silc_say,
600   silc_channel_message,
601   silc_private_message,
602   silc_notify,
603   silc_command,
604   silc_command_reply,
605   silc_connected,
606   silc_disconnected,
607   silc_get_auth_method,
608   silc_verify_public_key,
609   silc_ask_passphrase,
610   silc_failure,
611   silc_key_agreement,
612   silc_ftp,
613   silc_detach
614 };