The silc_client_connect_to_[server|client] and
[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 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   char *nickname;
32   SilcClientID client_id;
33   SilcUInt32 channel_count;
34   SilcUInt32 *cmd_idents;
35   SilcUInt32 cmd_idents_count;
36   SilcBool success;
37 } *SilcClientResumeSession;
38
39 /************************ Static utility functions **************************/
40
41 /* Command callback.  Nothing interesting to do here. */
42
43 static SilcBool
44 silc_client_register_command_called(SilcClient client,
45                                     SilcClientConnection conn,
46                                     SilcCommand command,
47                                     SilcStatus status,
48                                     SilcStatus error,
49                                     void *context,
50                                     va_list ap)
51 {
52   return FALSE;
53 }
54
55 /* Continues resuming after resolving.  Continue after last reply. */
56
57 static SilcBool
58 silc_client_resume_continue(SilcClient client,
59                             SilcClientConnection conn,
60                             SilcCommand command,
61                             SilcStatus status,
62                             SilcStatus error,
63                             void *context,
64                             va_list ap)
65 {
66   if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
67       SILC_STATUS_IS_ERROR(status)) {
68     silc_fsm_continue(&conn->internal->event_thread);
69     return FALSE;
70   }
71
72   return TRUE;
73 }
74
75 /****************************** NEW_ID packet *******************************/
76
77 /* Received new ID packet from server during registering to SILC network */
78
79 SILC_FSM_STATE(silc_client_new_id)
80 {
81   SilcClientConnection conn = fsm_context;
82   SilcClient client = conn->client;
83   SilcPacket packet = state_context;
84   SilcID id;
85
86   if (conn->local_id)
87     goto out;
88
89   SILC_LOG_DEBUG(("New ID received from server"));
90
91   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
92                                 silc_buffer_len(&packet->buffer), &id))
93     goto out;
94
95   SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
96                                               SILC_ID_CLIENT)));
97
98   /* Create local client entry */
99   conn->local_entry = silc_client_add_client(client, conn,
100                                              client->username,
101                                              client->username,
102                                              client->realname,
103                                              &id.u.client_id, 0);
104   if (!conn->local_entry)
105     goto out;
106
107   /* Save the ID */
108   conn->local_id = &conn->local_entry->id;
109   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
110
111   /* Save cache entry */
112   silc_mutex_lock(conn->internal->lock);
113   if (!silc_idcache_find_by_id_one(conn->internal->client_cache,
114                                    conn->local_id,
115                                    &conn->internal->local_entry)) {
116     silc_mutex_unlock(conn->internal->lock);
117     goto out;
118   }
119   silc_mutex_unlock(conn->internal->lock);
120
121   /* Save remote ID */
122   if (packet->src_id_len) {
123     conn->internal->remote_idp =
124       silc_id_payload_encode_data(packet->src_id,
125                                   packet->src_id_len,
126                                   packet->src_id_type);
127     if (!conn->internal->remote_idp)
128       goto out;
129     silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp),
130                              silc_buffer_len(conn->internal->remote_idp),
131                              &conn->remote_id);
132   }
133
134   /* Set IDs to the packet stream */
135   silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
136                       conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
137
138   /* Signal connection that new ID was received so it can continue
139      with the registering. */
140   if (conn->internal->registering)
141     silc_fsm_continue_sync(&conn->internal->event_thread);
142
143  out:
144   /** Packet processed */
145   silc_packet_free(packet);
146   return SILC_FSM_FINISH;
147 }
148
149
150 /************************ Register to SILC network **************************/
151
152 /* Register to network */
153
154 SILC_FSM_STATE(silc_client_st_register)
155 {
156   SilcClientConnection conn = fsm_context;
157   SilcClient client = conn->client;
158
159   SILC_LOG_DEBUG(("Register to network"));
160
161   /* Send NEW_CLIENT packet to register to network */
162   if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
163                            SILC_STR_UI_SHORT(strlen(client->username)),
164                            SILC_STR_DATA(client->username,
165                                          strlen(client->username)),
166                            SILC_STR_UI_SHORT(strlen(client->realname)),
167                            SILC_STR_DATA(client->realname,
168                                          strlen(client->realname)),
169                            SILC_STR_END)) {
170     /** Error sending packet */
171     silc_fsm_next(fsm, silc_client_st_register_error);
172     return SILC_FSM_CONTINUE;
173   }
174
175   /** Wait for new ID */
176   conn->internal->registering = TRUE;
177   silc_fsm_next_later(fsm, silc_client_st_register_complete,
178                       conn->internal->retry_timer, 0);
179   return SILC_FSM_WAIT;
180 }
181
182 /* Wait for NEW_ID packet to arrive */
183
184 SILC_FSM_STATE(silc_client_st_register_complete)
185 {
186   SilcClientConnection conn = fsm_context;
187   SilcClient client = conn->client;
188
189   if (conn->internal->aborted) {
190     /** Aborted */
191     silc_fsm_next(fsm, silc_client_st_register_error);
192     return SILC_FSM_CONTINUE;
193   }
194
195   if (conn->internal->disconnected) {
196     /** Disconnected */
197     silc_fsm_next(fsm, silc_client_st_register_error);
198     return SILC_FSM_CONTINUE;
199   }
200
201   if (!conn->local_id) {
202     if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
203       /** Timeout, ID not received */
204       conn->internal->registering = FALSE;
205       conn->internal->retry_count = 0;
206       conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
207       silc_fsm_next(fsm, silc_client_st_register_error);
208       return SILC_FSM_CONTINUE;
209     }
210
211     /** Resend registering packet */
212     silc_fsm_next(fsm, silc_client_st_register);
213     conn->internal->retry_timer = ((conn->internal->retry_timer *
214                                     SILC_CLIENT_RETRY_MUL) +
215                                    (silc_rng_get_rn16(client->rng) %
216                                     SILC_CLIENT_RETRY_RAND));
217     return SILC_FSM_CONTINUE;
218   }
219
220   SILC_LOG_DEBUG(("Registered to network"));
221
222   /* Issue IDENTIFY command for itself to get resolved hostname
223      correctly from server. */
224   silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
225                            silc_client_register_command_called, NULL,
226                            1, 5, silc_buffer_data(conn->internal->local_idp),
227                            silc_buffer_len(conn->internal->local_idp));
228
229   /* Call NICK command if the nickname was set by the application (and is
230      not same as the username). */
231   if (conn->internal->params.nickname &&
232       !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
233     silc_client_command_call(client, conn, NULL,
234                              "NICK", conn->internal->params.nickname, NULL);
235
236   /* Issue INFO command to fetch the real server name and server
237      information and other stuff. */
238   silc_client_command_send(client, conn, SILC_COMMAND_INFO,
239                            silc_client_register_command_called, NULL,
240                            1, 2, silc_buffer_data(conn->internal->remote_idp),
241                            silc_buffer_len(conn->internal->remote_idp));
242
243   /* Call connection callback.  We are now inside SILC network. */
244   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
245                  conn->callback_context);
246
247   conn->internal->registering = FALSE;
248   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
249                                 silc_client_connect_timeout, conn);
250
251   return SILC_FSM_FINISH;
252 }
253
254 /* Error registering to network */
255
256 SILC_FSM_STATE(silc_client_st_register_error)
257 {
258   SilcClientConnection conn = fsm_context;
259   SilcClient client = conn->client;
260
261   SILC_LOG_DEBUG(("Error registering to network"));
262
263   /* Signal to close connection */
264   if (!conn->internal->disconnected) {
265     conn->internal->disconnected = TRUE;
266     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
267   }
268
269   /* Call connect callback */
270   if (conn->internal->callback_called)
271     conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
272                    conn->callback_context);
273   conn->internal->callback_called = TRUE;
274
275   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
276                                 silc_client_connect_timeout, conn);
277
278   return SILC_FSM_FINISH;
279 }
280
281 /************************* Resume detached session **************************/
282
283 /* Resume detached session */
284
285 SILC_FSM_STATE(silc_client_st_resume)
286 {
287   SilcClientConnection conn = fsm_context;
288   SilcClient client = conn->client;
289   SilcClientResumeSession resume;
290   SilcBuffer auth;
291   unsigned char *id;
292   SilcUInt16 id_len;
293   int ret;
294
295   SILC_LOG_DEBUG(("Resuming detached session"));
296
297   resume = silc_calloc(1, sizeof(*resume));
298   if (!resume) {
299     /** Out of memory */
300     silc_fsm_next(fsm, silc_client_st_resume_error);
301     return SILC_FSM_CONTINUE;
302   }
303   silc_fsm_set_state_context(fsm, resume);
304
305   silc_buffer_set(&resume->detach, conn->internal->params.detach_data,
306                   conn->internal->params.detach_data_len);
307   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach),
308                    silc_buffer_len(&resume->detach));
309
310   /* Take the old client ID from the detachment data */
311   ret = silc_buffer_unformat(&resume->detach,
312                              SILC_STR_ADVANCE,
313                              SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname,
314                                                          NULL),
315                              SILC_STR_UI16_NSTRING(&id, &id_len),
316                              SILC_STR_UI_INT(NULL),
317                              SILC_STR_UI_INT(&resume->channel_count),
318                              SILC_STR_END);
319   if (ret < 0) {
320     /** Malformed detach data */
321     silc_fsm_next(fsm, silc_client_st_resume_error);
322     return SILC_FSM_CONTINUE;
323   }
324
325   if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &resume->client_id,
326                       sizeof(resume->client_id))) {
327     /** Malformed ID */
328     silc_fsm_next(fsm, silc_client_st_resume_error);
329     return SILC_FSM_CONTINUE;
330   }
331
332   /* Generate authentication data that server will verify */
333   auth = silc_auth_public_key_auth_generate(conn->public_key,
334                                             conn->private_key,
335                                             client->rng,
336                                             conn->internal->hash,
337                                             &resume->client_id,
338                                             SILC_ID_CLIENT);
339   if (!auth) {
340     /** Out of memory */
341     silc_fsm_next(fsm, silc_client_st_resume_error);
342     return SILC_FSM_CONTINUE;
343   }
344
345   /* Send RESUME_CLIENT packet to resume to network */
346   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
347                            SILC_STR_UI_SHORT(id_len),
348                            SILC_STR_DATA(id, id_len),
349                            SILC_STR_DATA(silc_buffer_data(auth),
350                                          silc_buffer_len(auth)),
351                            SILC_STR_END)) {
352     /** Error sending packet */
353     silc_fsm_next(fsm, silc_client_st_resume_error);
354     return SILC_FSM_CONTINUE;
355   }
356
357   /** Wait for new ID */
358   conn->internal->registering = TRUE;
359   silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
360   return SILC_FSM_WAIT;
361 }
362
363 /* Resolve the old session information, user mode and joined channels. */
364
365 SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
366 {
367   SilcClientConnection conn = fsm_context;
368   SilcClient client = conn->client;
369   SilcClientResumeSession resume = state_context;
370   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
371   unsigned char **res_argv = NULL;
372   int i;
373
374   if (!conn->local_id) {
375     /** Timeout, ID not received */
376     conn->internal->registering = FALSE;
377     silc_fsm_next(fsm, silc_client_st_resume_error);
378     return SILC_FSM_CONTINUE;
379   }
380
381   /* First, send UMODE command to get our own user mode in the network */
382   SILC_LOG_DEBUG(("Resolving user mode"));
383   silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
384                            silc_client_register_command_called, NULL,
385                            1, 1, silc_buffer_data(conn->internal->local_idp),
386                            silc_buffer_len(conn->internal->local_idp));
387
388   /* Second, send IDENTIFY command for all channels we know about.  These
389      are the channels we've joined to according our detachment data. */
390   for (i = 0; i < resume->channel_count; i++) {
391     SilcChannelID channel_id;
392     unsigned char *chid;
393     SilcUInt16 chid_len;
394     SilcBuffer idp;
395
396     if (silc_buffer_unformat(&resume->detach,
397                              SILC_STR_ADVANCE,
398                              SILC_STR_UI16_NSTRING(NULL, NULL),
399                              SILC_STR_UI16_NSTRING(&chid, &chid_len),
400                              SILC_STR_UI_INT(NULL),
401                              SILC_STR_END) < 0)
402       continue;
403
404     idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
405     if (!idp)
406       continue;
407     res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
408     res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
409                                  (res_argc + 1));
410     res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
411                                   (res_argc + 1));
412     res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
413     res_argv_types[res_argc] = res_argc + 5;
414     res_argc++;
415     silc_buffer_free(idp);
416   }
417
418   /* Send IDENTIFY command */
419   SILC_LOG_DEBUG(("Resolving joined channels"));
420   silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
421                                 silc_client_resume_continue, conn,
422                                 res_argc, res_argv, res_argv_lens,
423                                 res_argv_types);
424
425   for (i = 0; i < resume->channel_count; i++)
426     silc_free(res_argv[i]);
427   silc_free(res_argv);
428   silc_free(res_argv_lens);
429   silc_free(res_argv_types);
430
431   /** Wait for channels */
432   silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
433   return SILC_FSM_WAIT;
434 }
435
436 /* Resolve joined channel modes. */
437
438 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
439 {
440   SilcClientConnection conn = fsm_context;
441   SilcClientResumeSession resume = state_context;
442   SilcHashTableList htl;
443   SilcChannelUser chu;
444
445   SILC_LOG_DEBUG(("Resolving joined channel modes"));
446
447   silc_hash_table_list(conn->local_entry->channels, &htl);
448   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
449
450   }
451   silc_hash_table_list_reset(&htl);
452
453   return SILC_FSM_FINISH;
454 }
455
456 SILC_FSM_STATE(silc_client_st_resume_error)
457 {
458   /* XXX */
459   /* Close connection */
460
461   return SILC_FSM_FINISH;
462 }
463
464 /* Generates the session detachment data. This data can be used later
465    to resume back to the server. */
466
467 SilcBuffer silc_client_get_detach_data(SilcClient client,
468                                        SilcClientConnection conn)
469 {
470   SilcBuffer detach;
471   SilcHashTableList htl;
472   SilcChannelUser chu;
473   int ret, ch_count;
474
475   SILC_LOG_DEBUG(("Creating detachment data"));
476
477   ch_count = silc_hash_table_count(conn->local_entry->channels);
478
479   /* Save the nickname, Client ID and user mode in SILC network */
480   detach = silc_buffer_alloc(0);
481   if (!detach)
482     return NULL;
483   ret =
484     silc_buffer_format(detach,
485                        SILC_STR_ADVANCE,
486                        SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
487                        SILC_STR_DATA(conn->local_entry->nickname,
488                                      strlen(conn->local_entry->nickname)),
489                        SILC_STR_UI_SHORT(silc_buffer_len(conn->internal->
490                                                          local_idp)),
491                        SILC_STR_DATA(silc_buffer_data(conn->internal->
492                                                       local_idp),
493                                      silc_buffer_len(conn->internal->
494                                                      local_idp)),
495                        SILC_STR_UI_INT(conn->local_entry->mode),
496                        SILC_STR_UI_INT(ch_count),
497                        SILC_STR_END);
498   if (ret < 0) {
499     silc_buffer_free(detach);
500     return NULL;
501   }
502
503   /* Save all joined channels */
504   silc_hash_table_list(conn->local_entry->channels, &htl);
505   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
506     unsigned char chid[32];
507     SilcUInt32 chid_len;
508
509     silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid),
510                    &chid_len);
511     silc_buffer_format(detach,
512                        SILC_STR_ADVANCE,
513                        SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
514                        SILC_STR_DATA(chu->channel->channel_name,
515                                      strlen(chu->channel->channel_name)),
516                        SILC_STR_UI_SHORT(chid_len),
517                        SILC_STR_DATA(chid, chid_len),
518                        SILC_STR_UI_INT(chu->channel->mode),
519                        SILC_STR_END);
520     silc_free(chid);
521   }
522   silc_hash_table_list_reset(&htl);
523
524   silc_buffer_start(detach);
525   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach),
526                    silc_buffer_len(detach));
527
528   return detach;
529 }