Merge commit 'origin/silc.1.1.branch'
[silc.git] / lib / silcclient / client_register.c
1 /*
2
3   client_register.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2006 - 2007 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 "silc.h"
21 #include "silcclient.h"
22 #include "client_internal.h"
23
24 /************************** Types and definitions ***************************/
25
26 /* Resume session context */
27 typedef struct {
28   SilcClient client;
29   SilcClientConnection conn;
30   SilcBufferStruct detach;
31   SilcBuffer auth;
32   char *nickname;
33   unsigned char *id;
34   SilcUInt32 id_len;
35   SilcUInt32 channel_count;
36 } *SilcClientResumeSession;
37
38 /************************ Static utility functions **************************/
39
40 /* Continues resuming after resolving.  Continue after last reply. */
41
42 static SilcBool
43 silc_client_resume_continue(SilcClient client,
44                             SilcClientConnection conn,
45                             SilcCommand command,
46                             SilcStatus status,
47                             SilcStatus error,
48                             void *context,
49                             va_list ap)
50 {
51   if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
52       SILC_STATUS_IS_ERROR(status)) {
53     silc_fsm_continue(&conn->internal->event_thread);
54     return FALSE;
55   }
56
57   return TRUE;
58 }
59
60 /* Function used to call command replies back to application in resuming. */
61
62 static void
63 silc_client_resume_command_callback(SilcClient client,
64                                     SilcClientConnection conn,
65                                     SilcCommand command, ...)
66 {
67   va_list ap;
68   va_start(ap, command);
69   client->internal->ops->command_reply(client, conn, command,
70                                        SILC_STATUS_OK, SILC_STATUS_OK, ap);
71   va_end(ap);
72 }
73
74 /* Resume authentication data generation callback */
75
76 static void silc_client_resume_auth_generated(const SilcBuffer data,
77                                               void *context)
78 {
79   SilcClientConnection conn = context;
80   SilcClientResumeSession resume =
81     silc_fsm_get_state_context(&conn->internal->event_thread);
82
83   if (!data)
84     silc_fsm_next(&conn->internal->event_thread, silc_client_st_resume_error);
85   else
86     resume->auth = silc_buffer_copy(data);
87
88   SILC_FSM_CALL_CONTINUE_SYNC(&conn->internal->event_thread);
89 }
90
91
92 /****************************** NEW_ID packet *******************************/
93
94 /* Received new ID packet from server during registering to SILC network */
95
96 SILC_FSM_STATE(silc_client_new_id)
97 {
98   SilcClientConnection conn = fsm_context;
99   SilcClient client = conn->client;
100   SilcPacket packet = state_context;
101   char *nick;
102   SilcID id;
103
104   if (conn->local_id)
105     goto out;
106
107   SILC_LOG_DEBUG(("New ID received from server"));
108
109   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
110                                 silc_buffer_len(&packet->buffer), &id))
111     goto out;
112
113   SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
114                                               SILC_ID_CLIENT)));
115
116   /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */
117   if (conn->internal->remote_version >= 13)
118     nick = (conn->internal->params.nickname ?
119             conn->internal->params.nickname : client->username);
120   else
121     nick = client->username;
122
123   /* Create local client entry */
124   conn->local_entry = silc_client_add_client(client, conn, nick,
125                                              client->username,
126                                              client->realname,
127                                              &id.u.client_id, 0);
128   if (!conn->local_entry)
129     goto out;
130
131   /* Save the ID.  Take reference to conn->local_id. */
132   conn->local_id = &conn->local_entry->id;
133   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
134
135   /* Save remote ID */
136   if (packet->src_id_len) {
137     conn->internal->remote_idp =
138       silc_id_payload_encode_data(packet->src_id,
139                                   packet->src_id_len,
140                                   packet->src_id_type);
141     if (!conn->internal->remote_idp)
142       goto out;
143     silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp),
144                              silc_buffer_len(conn->internal->remote_idp),
145                              &conn->remote_id);
146   }
147
148   /* Set IDs to the packet stream */
149   silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
150                       conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
151
152   /* Signal connection that new ID was received so it can continue
153      with the registering. */
154   if (conn->internal->registering)
155     silc_fsm_continue_sync(&conn->internal->event_thread);
156
157  out:
158   /** Packet processed */
159   silc_packet_free(packet);
160   return SILC_FSM_FINISH;
161 }
162
163
164 /************************ Register to SILC network **************************/
165
166 /* Register to network */
167
168 SILC_FSM_STATE(silc_client_st_register)
169 {
170   SilcClientConnection conn = fsm_context;
171   SilcClient client = conn->client;
172   char *nick = NULL;
173
174   SILC_LOG_DEBUG(("Register to network"));
175
176   /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */
177   if (conn->internal->remote_version >= 13)
178     nick = (conn->internal->params.nickname ?
179             conn->internal->params.nickname : client->username);
180
181   /* Send NEW_CLIENT packet to register to network */
182   if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
183                            SILC_STR_UI_SHORT(strlen(client->username)),
184                            SILC_STR_DATA(client->username,
185                                          strlen(client->username)),
186                            SILC_STR_UI_SHORT(strlen(client->realname)),
187                            SILC_STR_DATA(client->realname,
188                                          strlen(client->realname)),
189                            SILC_STR_UI_SHORT(nick ? strlen(nick) : 0),
190                            SILC_STR_DATA(nick, nick ? strlen(nick) : 0),
191                            SILC_STR_END)) {
192     /** Error sending packet */
193     silc_fsm_next(fsm, silc_client_st_register_error);
194     return SILC_FSM_CONTINUE;
195   }
196
197   /** Wait for new ID */
198   conn->internal->registering = TRUE;
199   silc_fsm_next_later(fsm, silc_client_st_register_complete,
200                       conn->internal->retry_timer, 0);
201   return SILC_FSM_WAIT;
202 }
203
204 /* Wait for NEW_ID packet to arrive */
205
206 SILC_FSM_STATE(silc_client_st_register_complete)
207 {
208   SilcClientConnection conn = fsm_context;
209   SilcClient client = conn->client;
210
211   if (conn->internal->disconnected) {
212     /** Disconnected */
213     silc_fsm_next(fsm, silc_client_st_register_error);
214     return SILC_FSM_CONTINUE;
215   }
216
217   if (!conn->local_id) {
218     if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
219       /** Timeout, ID not received */
220       conn->internal->registering = FALSE;
221       conn->internal->retry_count = 0;
222       conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
223       silc_fsm_next(fsm, silc_client_st_register_error);
224       return SILC_FSM_CONTINUE;
225     }
226
227     /** Resend registering packet */
228     silc_fsm_next(fsm, silc_client_st_register);
229     conn->internal->retry_timer = ((conn->internal->retry_timer *
230                                     SILC_CLIENT_RETRY_MUL) +
231                                    (silc_rng_get_rn16(client->rng) %
232                                     SILC_CLIENT_RETRY_RAND));
233     return SILC_FSM_CONTINUE;
234   }
235
236   SILC_LOG_DEBUG(("Registered to network"));
237
238   /* Issue IDENTIFY command for itself to get resolved hostname
239      correctly from server. */
240   silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
241                            silc_client_command_called_dummy, NULL,
242                            1, 5, silc_buffer_data(conn->internal->local_idp),
243                            silc_buffer_len(conn->internal->local_idp));
244
245   /* With SILC protocol version 1.2 call NICK command if the nickname was
246      set by the application. */
247   if (conn->internal->params.nickname && conn->internal->remote_version < 13 &&
248       !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
249     silc_client_command_call(client, conn, NULL,
250                              "NICK", conn->internal->params.nickname, NULL);
251
252   /* Issue INFO command to fetch the real server name and server
253      information and other stuff. */
254   silc_client_command_send(client, conn, SILC_COMMAND_INFO,
255                            silc_client_command_called_dummy, NULL,
256                            1, 2, silc_buffer_data(conn->internal->remote_idp),
257                            silc_buffer_len(conn->internal->remote_idp));
258
259   /* Call connection callback.  We are now inside SILC network. */
260   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
261                  conn->callback_context);
262
263   conn->internal->registering = FALSE;
264   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
265                                 silc_client_connect_timeout, conn);
266   silc_async_free(conn->internal->cop);
267   conn->internal->cop = NULL;
268
269   return SILC_FSM_FINISH;
270 }
271
272 /* Error registering to network */
273
274 SILC_FSM_STATE(silc_client_st_register_error)
275 {
276   SilcClientConnection conn = fsm_context;
277
278   SILC_LOG_DEBUG(("Error registering to network"));
279
280   /* Signal to close connection */
281   conn->internal->status = SILC_CLIENT_CONN_ERROR;
282   if (!conn->internal->disconnected) {
283     conn->internal->disconnected = TRUE;
284     SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
285   }
286
287   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
288                                 silc_client_connect_timeout, conn);
289
290   return SILC_FSM_FINISH;
291 }
292
293 /************************* Resume detached session **************************/
294
295 /* Resume detached session */
296
297 SILC_FSM_STATE(silc_client_st_resume)
298 {
299   SilcClientConnection conn = fsm_context;
300   SilcClient client = conn->client;
301   SilcClientResumeSession resume;
302   unsigned char *id;
303   SilcUInt16 id_len;
304   SilcClientID client_id;
305   int ret;
306
307   SILC_LOG_DEBUG(("Resuming detached session"));
308
309   resume = silc_calloc(1, sizeof(*resume));
310   if (!resume) {
311     /** Out of memory */
312     silc_fsm_next(fsm, silc_client_st_resume_error);
313     return SILC_FSM_CONTINUE;
314   }
315   silc_fsm_set_state_context(fsm, resume);
316
317   silc_buffer_set(&resume->detach, conn->internal->params.detach_data,
318                   conn->internal->params.detach_data_len);
319   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach),
320                    silc_buffer_len(&resume->detach));
321
322   /* Take the old client ID from the detachment data */
323   ret = silc_buffer_unformat(&resume->detach,
324                              SILC_STR_ADVANCE,
325                              SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname,
326                                                          NULL),
327                              SILC_STR_UI16_NSTRING(&id, &id_len),
328                              SILC_STR_UI_INT(NULL),
329                              SILC_STR_UI_INT(&resume->channel_count),
330                              SILC_STR_END);
331   if (ret < 0) {
332     /** Malformed detach data */
333     SILC_LOG_DEBUG(("Malformed detachment data"));
334     silc_fsm_next(fsm, silc_client_st_resume_error);
335     return SILC_FSM_CONTINUE;
336   }
337
338   if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &client_id,
339                       sizeof(client_id))) {
340     /** Malformed ID */
341     SILC_LOG_DEBUG(("Malformed ID"));
342     silc_fsm_next(fsm, silc_client_st_resume_error);
343     return SILC_FSM_CONTINUE;
344   }
345   resume->id = id;
346   resume->id_len = id_len;
347
348   /* Generate authentication data that server will verify */
349   silc_fsm_next(fsm, silc_client_st_resume_send);
350   SILC_FSM_CALL(silc_auth_public_key_auth_generate(
351                                  conn->public_key, conn->private_key,
352                                  client->rng, conn->internal->hash,
353                                  &client_id, SILC_ID_CLIENT,
354                                  silc_client_resume_auth_generated, conn));
355   /* NOT REACHED */
356 }
357
358 /* Send RESUME_CLIENT packet */
359
360 SILC_FSM_STATE(silc_client_st_resume_send)
361 {
362   SilcClientConnection conn = fsm_context;
363   SilcClientResumeSession resume = state_context;
364
365   SILC_LOG_DEBUG(("Send RESUME_CLIENT packet"));
366
367   /* Send RESUME_CLIENT packet to resume to network */
368   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
369                            SILC_STR_UI_SHORT(resume->id_len),
370                            SILC_STR_DATA(resume->id, resume->id_len),
371                            SILC_STR_DATA(silc_buffer_data(resume->auth),
372                                          silc_buffer_len(resume->auth)),
373                            SILC_STR_END)) {
374     /** Error sending packet */
375     SILC_LOG_DEBUG(("Error sending packet"));
376     silc_fsm_next(fsm, silc_client_st_resume_error);
377     return SILC_FSM_CONTINUE;
378   }
379
380   /** Wait for new ID */
381   conn->internal->registering = TRUE;
382   silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
383   return SILC_FSM_WAIT;
384 }
385
386 /* Resolve the old session information, user mode and joined channels. */
387
388 SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
389 {
390   SilcClientConnection conn = fsm_context;
391   SilcClient client = conn->client;
392   SilcClientResumeSession resume = state_context;
393   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
394   unsigned char **res_argv = NULL;
395   int i;
396
397   if (conn->internal->disconnected) {
398     /** Disconnected */
399     silc_fsm_next(fsm, silc_client_st_resume_error);
400     return SILC_FSM_CONTINUE;
401   }
402
403   if (!conn->local_id) {
404     /** Timeout, ID not received */
405     conn->internal->registering = FALSE;
406     silc_fsm_next(fsm, silc_client_st_resume_error);
407     return SILC_FSM_CONTINUE;
408   }
409
410   /** Wait for channels */
411   silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
412
413   /* Change our nickname */
414   silc_client_change_nickname(client, conn, conn->local_entry,
415                               resume->nickname, NULL, NULL, 0);
416
417   /* Send UMODE command to get our own user mode in the network */
418   SILC_LOG_DEBUG(("Resolving user mode"));
419   silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
420                            silc_client_command_called_dummy, NULL,
421                            1, 1, silc_buffer_data(conn->internal->local_idp),
422                            silc_buffer_len(conn->internal->local_idp));
423
424   if (!resume->channel_count)
425     return SILC_FSM_YIELD;
426
427   /* Send IDENTIFY command for all channels we know about.  These are the
428      channels we've joined to according our detachment data. */
429   for (i = 0; i < resume->channel_count; i++) {
430     SilcChannelEntry channel;
431     unsigned char *chid;
432     SilcUInt16 chid_len;
433     SilcBuffer idp;
434     SilcChannelID channel_id;
435     char *name;
436
437     if (silc_buffer_unformat(&resume->detach,
438                              SILC_STR_ADVANCE,
439                              SILC_STR_UI16_NSTRING(&name, NULL),
440                              SILC_STR_UI16_NSTRING(&chid, &chid_len),
441                              SILC_STR_UI_INT(NULL),
442                              SILC_STR_END) < 0)
443       continue;
444
445     if (!silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL, &channel_id,
446                         sizeof(channel_id)))
447       continue;
448     idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
449     if (!idp)
450       continue;
451
452     /* Add the channel to cache */
453     channel = silc_client_get_channel_by_id(client, conn, &channel_id);
454     if (!channel)
455       silc_client_add_channel(client, conn, name, 0, &channel_id);
456     else
457       silc_client_unref_channel(client, conn, channel);
458
459     res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
460     res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
461                                  (res_argc + 1));
462     res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
463                                   (res_argc + 1));
464     res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
465     res_argv_types[res_argc] = res_argc + 5;
466     res_argc++;
467     silc_buffer_free(idp);
468   }
469
470   /* Send IDENTIFY command */
471   SILC_LOG_DEBUG(("Resolving joined channels"));
472   silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
473                                 silc_client_resume_continue, conn,
474                                 res_argc, res_argv, res_argv_lens,
475                                 res_argv_types);
476
477   for (i = 0; i < resume->channel_count; i++)
478     silc_free(res_argv[i]);
479   silc_free(res_argv);
480   silc_free(res_argv_lens);
481   silc_free(res_argv_types);
482
483   return SILC_FSM_WAIT;
484 }
485
486 /* Resolve joined channel modes, users and topics. */
487
488 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
489 {
490   SilcClientConnection conn = fsm_context;
491   SilcClient client = conn->client;
492   SilcClientResumeSession resume = state_context;
493   SilcIDCacheEntry entry;
494   SilcChannelEntry channel;
495   SilcList channels;
496   SilcBuffer idp;
497
498   if (conn->internal->disconnected) {
499     /** Disconnected */
500     silc_fsm_next(fsm, silc_client_st_resume_error);
501     return SILC_FSM_CONTINUE;
502   }
503
504   SILC_LOG_DEBUG(("Resolving channel details"));
505
506   /** Wait for channel modes */
507   silc_fsm_next(fsm, silc_client_st_resume_completed);
508
509   if (!silc_idcache_get_all(conn->internal->channel_cache, &channels))
510     return SILC_FSM_YIELD;
511
512   /* Resolve channels' mode, users and topic */
513   resume->channel_count = silc_list_count(channels) * 3;
514   silc_list_start(channels);
515   while ((entry = silc_list_get(channels))) {
516     channel = entry->context;
517     idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
518     if (!idp)
519       continue;
520
521     silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
522                              silc_client_resume_continue, conn, 1,
523                              1, silc_buffer_data(idp),
524                              silc_buffer_len(idp));
525     silc_client_command_send(client, conn, SILC_COMMAND_USERS,
526                              silc_client_resume_continue, conn, 1,
527                              1, silc_buffer_data(idp),
528                              silc_buffer_len(idp));
529     silc_client_command_send(client, conn, SILC_COMMAND_TOPIC,
530                              silc_client_resume_continue, conn, 1,
531                              1, silc_buffer_data(idp),
532                              silc_buffer_len(idp));
533     silc_buffer_free(idp);
534   }
535
536   return SILC_FSM_WAIT;
537 }
538
539 /* Resuming completed */
540
541 SILC_FSM_STATE(silc_client_st_resume_completed)
542 {
543   SilcClientConnection conn = fsm_context;
544   SilcClient client = conn->client;
545   SilcClientResumeSession resume = state_context;
546   SilcIDCacheEntry entry;
547   SilcChannelEntry channel;
548   SilcList channels;
549
550   if (conn->internal->disconnected) {
551     /** Disconnected */
552     silc_fsm_next(fsm, silc_client_st_resume_error);
553     return SILC_FSM_CONTINUE;
554   }
555
556   if (resume->channel_count > 0) {
557     resume->channel_count--;
558     if (resume->channel_count)
559       return SILC_FSM_WAIT;
560   }
561
562   SILC_LOG_DEBUG(("Resuming completed"));
563
564   /* Issue IDENTIFY command for itself to get resolved hostname
565      correctly from server. */
566   silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
567                            silc_client_command_called_dummy, NULL,
568                            1, 5, silc_buffer_data(conn->internal->local_idp),
569                            silc_buffer_len(conn->internal->local_idp));
570
571   /* Issue INFO command to fetch the real server name and server
572      information and other stuff. */
573   silc_client_command_send(client, conn, SILC_COMMAND_INFO,
574                            silc_client_command_called_dummy, NULL,
575                            1, 2, silc_buffer_data(conn->internal->remote_idp),
576                            silc_buffer_len(conn->internal->remote_idp));
577
578   /* Call connection callback.  We have now resumed to SILC network. */
579   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS_RESUME, 0, NULL,
580                  conn->callback_context);
581
582   /* Call UMODE command reply. */
583   if (conn->local_entry->mode)
584     silc_client_resume_command_callback(client, conn, SILC_COMMAND_UMODE,
585                                         conn->local_entry->mode);
586
587   /* Call NICK command reply. */
588   silc_client_resume_command_callback(client, conn, SILC_COMMAND_NICK,
589                                       conn->local_entry,
590                                       conn->local_entry->nickname,
591                                       &conn->local_entry->id);
592
593   /* Call JOIN command replies for all joined channel */
594   if (silc_idcache_get_all(conn->internal->channel_cache, &channels)) {
595     silc_list_start(channels);
596     while ((entry = silc_list_get(channels))) {
597       SilcHashTableList htl;
598       const char *cipher, *hmac;
599
600       channel = entry->context;
601       cipher = (channel->internal.send_key ?
602                 silc_cipher_get_name(channel->internal.send_key) : NULL);
603       hmac = (channel->internal.hmac ?
604               silc_hmac_get_name(channel->internal.hmac) : NULL);
605       silc_hash_table_list(channel->user_list, &htl);
606       silc_client_resume_command_callback(client, conn, SILC_COMMAND_JOIN,
607                                           channel->channel_name, channel,
608                                           channel->mode, &htl, channel->topic,
609                                           cipher, hmac, channel->founder_key,
610                                           channel->channel_pubkeys,
611                                           channel->user_limit);
612       silc_hash_table_list_reset(&htl);
613     }
614   }
615
616   conn->internal->registering = FALSE;
617   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
618                                 silc_client_connect_timeout, conn);
619   silc_free(resume->nickname);
620   silc_free(resume);
621   silc_async_free(conn->internal->cop);
622   conn->internal->cop = NULL;
623
624   return SILC_FSM_FINISH;
625 }
626
627 /* Error resuming to network */
628
629 SILC_FSM_STATE(silc_client_st_resume_error)
630 {
631   SilcClientConnection conn = fsm_context;
632   SilcClientResumeSession resume = state_context;
633
634   if (conn->internal->disconnected) {
635     if (resume) {
636       silc_free(resume->nickname);
637       silc_free(resume);
638     }
639     return SILC_FSM_FINISH;
640   }
641
642   SILC_LOG_DEBUG(("Error resuming to network"));
643
644   /* Signal to close connection */
645   conn->internal->status = SILC_CLIENT_CONN_ERROR;
646   if (!conn->internal->disconnected) {
647     conn->internal->disconnected = TRUE;
648     SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
649   }
650
651   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
652                                 silc_client_connect_timeout, conn);
653
654   if (resume) {
655     silc_free(resume->nickname);
656     silc_free(resume);
657   }
658
659   return SILC_FSM_FINISH;
660 }
661
662 /* Generates the session detachment data. This data can be used later
663    to resume back to the server. */
664
665 SilcBuffer silc_client_get_detach_data(SilcClient client,
666                                        SilcClientConnection conn)
667 {
668   SilcBuffer detach;
669   SilcHashTableList htl;
670   SilcChannelUser chu;
671   unsigned char id[64];
672   SilcUInt32 id_len;
673   int ret, ch_count;
674
675   SILC_LOG_DEBUG(("Creating detachment data"));
676
677   ch_count = silc_hash_table_count(conn->local_entry->channels);
678   silc_id_id2str(conn->local_id, SILC_ID_CLIENT, id, sizeof(id), &id_len);
679
680   /* Save the nickname, Client ID and user mode in SILC network */
681   detach = silc_buffer_alloc(0);
682   if (!detach)
683     return NULL;
684   ret =
685     silc_buffer_format(detach,
686                        SILC_STR_ADVANCE,
687                        SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
688                        SILC_STR_DATA(conn->local_entry->nickname,
689                                      strlen(conn->local_entry->nickname)),
690                        SILC_STR_UI_SHORT(id_len),
691                        SILC_STR_DATA(id, id_len),
692                        SILC_STR_UI_INT(conn->local_entry->mode),
693                        SILC_STR_UI_INT(ch_count),
694                        SILC_STR_END);
695   if (ret < 0) {
696     silc_buffer_free(detach);
697     return NULL;
698   }
699
700   /* Save all joined channels */
701   silc_hash_table_list(conn->local_entry->channels, &htl);
702   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
703     unsigned char chid[32];
704     SilcUInt32 chid_len;
705
706     silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid),
707                    &chid_len);
708     silc_buffer_format(detach,
709                        SILC_STR_ADVANCE,
710                        SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
711                        SILC_STR_DATA(chu->channel->channel_name,
712                                      strlen(chu->channel->channel_name)),
713                        SILC_STR_UI_SHORT(chid_len),
714                        SILC_STR_DATA(chid, chid_len),
715                        SILC_STR_UI_INT(chu->channel->mode),
716                        SILC_STR_END);
717   }
718   silc_hash_table_list_reset(&htl);
719
720   silc_buffer_start(detach);
721   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach),
722                    silc_buffer_len(detach));
723
724   return detach;
725 }