updates.
[silc.git] / lib / silcclient / command.c
1 /*
2
3   command.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 #define SILC_NOT_CONNECTED(x, c) \
26   x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
27            "You are not connected to a server, use /SERVER to connect");
28
29 /* Command operation that is called at the end of all commands. 
30    Usage: COMMAND(status); */
31 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
32   cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
33
34 /* Error to application. Usage: COMMAND_ERROR(status); */
35 #define COMMAND_ERROR(status)                           \
36   cmd->client->internal->ops->command(cmd->client,      \
37   cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
38
39 #define SAY cmd->client->internal->ops->say
40
41 /* Generic function to send any command. The arguments must be sent already
42    encoded into correct form and in correct order. */
43
44 void silc_client_command_send(SilcClient client, SilcClientConnection conn,
45                               SilcCommand command, SilcUInt16 ident,
46                               SilcUInt32 argc, ...)
47 {
48   SilcBuffer packet;
49   va_list ap;
50
51   va_start(ap, argc);
52
53   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
54   silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
55                           NULL, 0, NULL, NULL, packet->data, 
56                           packet->len, TRUE);
57   silc_buffer_free(packet);
58 }
59
60 /* Finds and returns a pointer to the command list. Return NULL if the
61    command is not found. */
62
63 SilcClientCommand silc_client_command_find(SilcClient client,
64                                            const char *name)
65 {
66   SilcClientCommand cmd;
67
68   silc_list_start(client->internal->commands);
69   while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
70     if (cmd->name && !strcmp(cmd->name, name))
71       return cmd;
72   }
73
74   return NULL;
75 }
76
77 /* Calls the command (executes it).  Application can call this after
78    it has allocated the SilcClientCommandContext with the function
79    silc_client_command_alloc and found the command from the client
80    library by calling silc_client_command_find.  This will execute
81    the command. */
82
83 void silc_client_command_call(SilcClientCommand command, 
84                               SilcClientCommandContext cmd)
85 {
86   (*command->command)((void *)cmd, NULL);
87 }
88
89 /* Add new pending command to be executed when reply to a command has been
90    received. The `reply_cmd' is the command that will call the `callback'
91    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
92    to match any command with the `ident'.  If `ident' is non-zero
93    the `callback' will be executed when received reply with command
94    identifier `ident'. If there already exists pending command for the
95    specified command, ident, callback and context this function has no
96    effect. */
97
98 void silc_client_command_pending(SilcClientConnection conn,
99                                  SilcCommand reply_cmd,
100                                  SilcUInt16 ident,
101                                  SilcCommandCb callback,
102                                  void *context)
103 {
104   SilcClientCommandPending *reply;
105
106   /* Check whether identical pending already exists for same command,
107      ident, callback and callback context. If it does then it would be
108      error to register it again. */
109   silc_dlist_start(conn->pending_commands);
110   while ((reply = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
111     if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
112         reply->callback == callback && reply->context == context)
113       return;
114   }
115
116   reply = silc_calloc(1, sizeof(*reply));
117   reply->reply_cmd = reply_cmd;
118   reply->ident = ident;
119   reply->context = context;
120   reply->callback = callback;
121   silc_dlist_add(conn->pending_commands, reply);
122 }
123
124 /* Deletes pending command by reply command type. */
125
126 void silc_client_command_pending_del(SilcClientConnection conn,
127                                      SilcCommand reply_cmd,
128                                      SilcUInt16 ident)
129 {
130   SilcClientCommandPending *r;
131
132   if (!conn->pending_commands)
133     return;
134
135   silc_dlist_start(conn->pending_commands);
136   while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
137     if (r->reply_cmd == reply_cmd && r->ident == ident) {
138       silc_dlist_del(conn->pending_commands, r);
139       break;
140     }
141   }
142 }
143
144 /* Checks for pending commands and marks callbacks to be called from
145    the command reply function. */
146
147 SilcClientCommandPendingCallbacks
148 silc_client_command_pending_check(SilcClientConnection conn,
149                                   SilcClientCommandReplyContext ctx,
150                                   SilcCommand command, 
151                                   SilcUInt16 ident,
152                                   SilcUInt32 *callbacks_count)
153 {
154   SilcClientCommandPending *r;
155   SilcClientCommandPendingCallbacks callbacks = NULL;
156   int i = 0;
157
158   silc_dlist_start(conn->pending_commands);
159   while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
160     if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
161         && r->ident == ident) {
162       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
163       callbacks[i].context = r->context;
164       callbacks[i].callback = r->callback;
165       ctx->ident = ident;
166       i++;
167     }
168   }
169
170   *callbacks_count = i;
171   return callbacks;
172 }
173
174 /* Allocate Command Context */
175
176 SilcClientCommandContext silc_client_command_alloc(void)
177 {
178   SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
179   ctx->users++;
180   return ctx;
181 }
182
183 /* Free command context and its internals */
184
185 void silc_client_command_free(SilcClientCommandContext ctx)
186 {
187   ctx->users--;
188   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
189                   ctx->users));
190   if (ctx->users < 1) {
191     int i;
192
193     for (i = 0; i < ctx->argc; i++)
194       silc_free(ctx->argv[i]);
195     silc_free(ctx->argv_lens);
196     silc_free(ctx->argv_types);
197     silc_free(ctx);
198   }
199 }
200
201 /* Duplicate Command Context by adding reference counter. The context won't
202    be free'd untill it hits zero. */
203
204 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
205 {
206   ctx->users++;
207   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
208                   ctx->users));
209   return ctx;
210 }
211
212 /* Command WHOIS. This command is used to query information about 
213    specific user. */
214
215 SILC_CLIENT_CMD_FUNC(whois)
216 {
217   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
218   SilcClientConnection conn = cmd->conn;
219   SilcBuffer buffer;
220   unsigned char count[4];
221
222   if (!cmd->conn) {
223     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
224     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
225     goto out;
226   }
227
228   /* Given without arguments fetches client's own information */
229   if (cmd->argc < 2) {
230     buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
231     silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, 
232                              ++conn->cmd_ident,
233                              1, 4, buffer->data, buffer->len);
234     silc_buffer_free(buffer);
235     goto out;
236   }
237
238   if (cmd->argc == 2) {
239     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
240                                             ++conn->cmd_ident, 1,
241                                             1, cmd->argv[1], 
242                                             cmd->argv_lens[1]);
243   } else {
244     int c = atoi(cmd->argv[2]);
245     memset(count, 0, sizeof(count));
246     SILC_PUT32_MSB(c, count);
247     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
248                                             ++conn->cmd_ident, 2,
249                                             1, cmd->argv[1], cmd->argv_lens[1],
250                                             2, count, sizeof(count));
251   }
252   silc_client_packet_send(cmd->client, cmd->conn->sock,
253                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
254                           buffer->data, buffer->len, TRUE);
255   silc_buffer_free(buffer);
256
257   /* Notify application */
258   COMMAND(SILC_STATUS_OK);
259
260  out:
261   silc_client_command_free(cmd);
262 }
263
264 /* Command WHOWAS. This command is used to query history information about
265    specific user that used to exist in the network. */
266
267 SILC_CLIENT_CMD_FUNC(whowas)
268 {
269   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
270   SilcClientConnection conn = cmd->conn;
271   SilcBuffer buffer;
272   unsigned char count[4];
273
274   if (!cmd->conn) {
275     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
276     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
277     goto out;
278   }
279
280   if (cmd->argc < 2 || cmd->argc > 3) {
281     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
282         "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
283     COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
284                    SILC_STATUS_ERR_TOO_MANY_PARAMS));
285     goto out;
286   }
287
288   if (cmd->argc == 2) {
289     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
290                                             ++conn->cmd_ident, 1,
291                                             1, cmd->argv[1], 
292                                             cmd->argv_lens[1]);
293   } else {
294     int c = atoi(cmd->argv[2]);
295     memset(count, 0, sizeof(count));
296     SILC_PUT32_MSB(c, count);
297     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
298                                             ++conn->cmd_ident, 2,
299                                             1, cmd->argv[1], cmd->argv_lens[1],
300                                             2, count, sizeof(count));
301   }
302   silc_client_packet_send(cmd->client, cmd->conn->sock,
303                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
304                           buffer->data, buffer->len, TRUE);
305   silc_buffer_free(buffer);
306
307   /* Notify application */
308   COMMAND(SILC_STATUS_OK);
309
310  out:
311   silc_client_command_free(cmd);
312 }
313
314 /* Command IDENTIFY. This command is used to query information about 
315    specific user, especially ID's. 
316
317    NOTE: This command is used only internally by the client library
318    and application MUST NOT call this command directly. */
319
320 SILC_CLIENT_CMD_FUNC(identify)
321 {
322   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
323   SilcClientConnection conn = cmd->conn;
324   SilcBuffer buffer;
325   unsigned char count[4];
326
327   if (!cmd->conn) {
328     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
329     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
330     goto out;
331   }
332
333   if (cmd->argc < 2 || cmd->argc > 3)
334     goto out;
335
336   if (cmd->argc == 2) {
337     buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
338                                             ++conn->cmd_ident, 1,
339                                             1, cmd->argv[1],
340                                             cmd->argv_lens[1]);
341   } else {
342     int c = atoi(cmd->argv[2]);
343     memset(count, 0, sizeof(count));
344     SILC_PUT32_MSB(c, count);
345     buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
346                                             ++conn->cmd_ident, 2,
347                                             1, cmd->argv[1],
348                                             cmd->argv_lens[1],
349                                             4, count, sizeof(count));
350   }
351
352   silc_client_packet_send(cmd->client, cmd->conn->sock,
353                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
354                           buffer->data, buffer->len, TRUE);
355   silc_buffer_free(buffer);
356
357  out:
358   silc_client_command_free(cmd);
359 }
360
361 /* Command NICK. Shows current nickname/sets new nickname on current
362    window. */
363
364 SILC_CLIENT_CMD_FUNC(nick)
365 {
366   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
367   SilcClientConnection conn = cmd->conn;
368   SilcBuffer buffer;
369
370   if (!cmd->conn) {
371     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
372     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
373     goto out;
374   }
375
376   if (cmd->argc < 2) {
377     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
378         "Usage: /NICK <nickname>");
379     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
380     goto out;
381   }
382
383   if (!strcmp(conn->nickname, cmd->argv[1]))
384     goto out;
385
386   /* Show current nickname */
387   if (cmd->argc < 2) {
388     if (cmd->conn) {
389       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
390           "Your nickname is %s on server %s", 
391           conn->nickname, conn->remote_host);
392     } else {
393       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
394           "Your nickname is %s", conn->nickname);
395     }
396
397     COMMAND(SILC_STATUS_OK);
398     goto out;
399   }
400
401   if (cmd->argv_lens[1] > 128)
402     cmd->argv_lens[1] = 128;
403
404   /* Send the NICK command */
405   buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
406                                        &cmd->argv[1],
407                                        &cmd->argv_lens[1], 
408                                        &cmd->argv_types[1],
409                                        ++cmd->conn->cmd_ident);
410   silc_client_packet_send(cmd->client, cmd->conn->sock,
411                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
412                           buffer->data, buffer->len, TRUE);
413   silc_buffer_free(buffer);
414
415  out:
416   silc_client_command_free(cmd);
417 }
418
419 /* Command LIST. Lists channels on the current server. */
420
421 SILC_CLIENT_CMD_FUNC(list)
422 {
423   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
424   SilcClientConnection conn = cmd->conn;
425   SilcIDCacheEntry id_cache = NULL;
426   SilcChannelEntry channel;
427   SilcBuffer buffer, idp = NULL;
428   char *name;
429
430   if (!cmd->conn) {
431     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
432     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
433     goto out;
434   }
435
436   if (cmd->argc == 2) {
437     name = cmd->argv[1];
438
439     /* Get the Channel ID of the channel */
440     if (silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
441       channel = (SilcChannelEntry)id_cache->context;
442       idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
443     }
444   }
445
446   if (!idp)
447     buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
448                                             ++conn->cmd_ident, 0);
449   else
450     buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
451                                             ++conn->cmd_ident, 1,
452                                             1, idp->data, idp->len);
453
454   silc_client_packet_send(cmd->client, cmd->conn->sock,
455                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
456                           buffer->data, buffer->len, TRUE);
457   silc_buffer_free(buffer);
458   if (idp)
459     silc_buffer_free(idp);
460
461   /* Notify application */
462   COMMAND(SILC_STATUS_OK);
463
464  out:
465   silc_client_command_free(cmd);
466 }
467
468 /* Command TOPIC. Sets/shows topic on a channel. */
469
470 SILC_CLIENT_CMD_FUNC(topic)
471 {
472   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
473   SilcClientConnection conn = cmd->conn;
474   SilcIDCacheEntry id_cache = NULL;
475   SilcChannelEntry channel;
476   SilcBuffer buffer, idp;
477   char *name;
478
479   if (!cmd->conn) {
480     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
481     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
482     goto out;
483   }
484
485   if (cmd->argc < 2 || cmd->argc > 3) {
486     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
487         "Usage: /TOPIC <channel> [<topic>]");
488     COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
489                    SILC_STATUS_ERR_TOO_MANY_PARAMS));
490     goto out;
491   }
492
493   if (cmd->argv[1][0] == '*') {
494     if (!conn->current_channel) {
495       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
496           "You are not on any channel");
497       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
498       goto out;
499     }
500     name = conn->current_channel->channel_name;
501   } else {
502     name = cmd->argv[1];
503   }
504
505   if (!conn->current_channel) {
506     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
507         "You are not on that channel");
508     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
509     goto out;
510   }
511
512   /* Get the Channel ID of the channel */
513   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
514     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
515         "You are not on that channel");
516     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
517     goto out;
518   }
519
520   channel = (SilcChannelEntry)id_cache->context;
521
522   /* Send TOPIC command to the server */
523   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
524   if (cmd->argc > 2)
525     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
526                                             ++conn->cmd_ident, 2, 
527                                             1, idp->data, idp->len,
528                                             2, cmd->argv[2], 
529                                             strlen(cmd->argv[2]));
530   else
531     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
532                                             ++conn->cmd_ident, 1,
533                                             1, idp->data, idp->len);
534   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
535                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
536   silc_buffer_free(buffer);
537   silc_buffer_free(idp);
538
539   /* Notify application */
540   COMMAND(SILC_STATUS_OK);
541
542  out:
543   silc_client_command_free(cmd);
544 }
545
546 /* Command INVITE. Invites specific client to join a channel. This is
547    also used to mange the invite list of the channel. */
548
549 SILC_CLIENT_CMD_FUNC(invite)
550 {
551   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
552   SilcClient client = cmd->client;
553   SilcClientConnection conn = cmd->conn;
554   SilcClientEntry client_entry = NULL;
555   SilcChannelEntry channel;
556   SilcBuffer buffer, clidp, chidp;
557   SilcUInt32 type = 0;
558   char *nickname = NULL, *name;
559   char *invite = NULL;
560
561   if (!cmd->conn) {
562     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
563     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
564     goto out;
565   }
566
567   if (cmd->argc < 2) {
568     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
569         "Usage: /INVITE <channel> [<nickname>[@server>]"
570         "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
571     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
572     goto out;
573   }
574
575   if (cmd->argv[1][0] == '*') {
576     if (!conn->current_channel) {
577       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
578           "You are not on any channel");
579       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
580       goto out;
581     }
582
583     channel = conn->current_channel;
584   } else {
585     name = cmd->argv[1];
586
587     channel = silc_client_get_channel(cmd->client, conn, name);
588     if (!channel) {
589       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
590           "You are on that channel");
591       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
592       goto out;
593     }
594   }
595
596   /* Parse the typed nickname. */
597   if (cmd->argc == 3) {
598     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
599       if (client->internal->params->nickname_parse)
600         client->internal->params->nickname_parse(cmd->argv[2], &nickname);
601       else
602         nickname = strdup(cmd->argv[2]);
603
604       /* Find client entry */
605       client_entry = silc_idlist_get_client(client, conn, nickname, 
606                                             cmd->argv[2], TRUE);
607       if (!client_entry) {
608         if (cmd->pending) {
609           COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
610           goto out;
611         }
612       
613         /* Client entry not found, it was requested thus mark this to be
614            pending command. */
615         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
616                                     conn->cmd_ident,
617                                     silc_client_command_invite, 
618                                     silc_client_command_dup(cmd));
619         cmd->pending = 1;
620         goto out;
621       }
622     } else {
623       invite = cmd->argv[2];
624       invite++;
625       if (cmd->argv[2][0] == '+')
626         type = 3;
627       else
628         type = 4;
629     }
630   }
631
632   /* Send the command */
633   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
634   if (client_entry) {
635     clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
636     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
637                                             ++conn->cmd_ident, 3,
638                                             1, chidp->data, chidp->len,
639                                             2, clidp->data, clidp->len,
640                                             type, invite, invite ?
641                                             strlen(invite) : 0);
642     silc_buffer_free(clidp);
643   } else {
644     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
645                                             ++conn->cmd_ident, 2,
646                                             1, chidp->data, chidp->len,
647                                             type, invite, invite ?
648                                             strlen(invite) : 0);
649   }
650
651   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
652                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
653   silc_buffer_free(buffer);
654   silc_buffer_free(chidp);
655
656   /* Notify application */
657   COMMAND(SILC_STATUS_OK);
658
659  out:
660   silc_free(nickname);
661   silc_client_command_free(cmd);
662 }
663
664 typedef struct {
665   SilcClient client;
666   SilcClientConnection conn;
667 } *QuitInternal;
668
669 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
670 {
671   QuitInternal q = (QuitInternal)context;
672
673   /* Close connection */
674   q->client->internal->ops->disconnect(q->client, q->conn);
675   silc_client_close_connection(q->client, q->conn->sock->user_data);
676
677   silc_free(q);
678 }
679
680 /* Command QUIT. Closes connection with current server. */
681  
682 SILC_CLIENT_CMD_FUNC(quit)
683 {
684   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
685   SilcBuffer buffer;
686   QuitInternal q;
687
688   if (!cmd->conn) {
689     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
690     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
691     goto out;
692   }
693
694   if (cmd->argc > 1)
695     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, 
696                                          &cmd->argv[1], &cmd->argv_lens[1],
697                                          &cmd->argv_types[1], 0);
698   else
699     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
700                                          NULL, NULL, NULL, 0);
701   silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, 
702                           NULL, 0, NULL, NULL, 
703                           buffer->data, buffer->len, TRUE);
704   silc_buffer_free(buffer);
705
706   q = silc_calloc(1, sizeof(*q));
707   q->client = cmd->client;
708   q->conn = cmd->conn;
709
710   /* Sleep for a while */
711   sleep(2);
712
713   /* We quit the connection with little timeout */
714   silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
715                          silc_client_command_quit_cb, (void *)q,
716                          1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
717
718   /* Notify application */
719   COMMAND(SILC_STATUS_OK);
720
721  out:
722   silc_client_command_free(cmd);
723 }
724
725 /* Timeout callback to remove the killed client from cache */
726
727 SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
728 {
729   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
730   SilcClient client = cmd->client;
731   SilcClientConnection conn = cmd->conn;
732   SilcClientEntry target;
733   char *nickname = NULL;
734   
735   /* Parse the typed nickname. */
736   if (client->internal->params->nickname_parse)
737     client->internal->params->nickname_parse(cmd->argv[1], &nickname);
738   else
739     nickname = strdup(cmd->argv[1]);
740
741   /* Get the target client */
742   target = silc_idlist_get_client(cmd->client, conn, nickname, 
743                                   cmd->argv[1], FALSE);
744   if (target)
745     /* Remove the client from all channels and free it */
746     silc_client_del_client(client, conn, target);
747
748   silc_free(nickname);
749   silc_client_command_free(cmd);
750 }
751
752 /* Kill command's pending command callback to actually remove the killed
753    client from our local cache. */
754
755 SILC_CLIENT_CMD_FUNC(kill_remove)
756 {
757   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
758   SilcClientCommandReplyContext reply = 
759     (SilcClientCommandReplyContext)context2;
760   SilcStatus status;
761
762   silc_command_get_status(reply->payload, &status, NULL);
763   if (status == SILC_STATUS_OK) {
764     /* Remove with timeout */
765     silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
766                            silc_client_command_kill_remove_later, context,
767                            1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
768     return;
769   }
770
771   silc_client_command_free(cmd);
772 }
773
774 /* Command KILL. Router operator can use this command to remove an client
775    fromthe SILC Network. */
776
777 SILC_CLIENT_CMD_FUNC(kill)
778 {
779   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
780   SilcClient client = cmd->client;
781   SilcClientConnection conn = cmd->conn;
782   SilcBuffer buffer, idp;
783   SilcClientEntry target;
784   char *nickname = NULL;
785
786   if (!cmd->conn) {
787     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
788     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
789     goto out;
790   }
791
792   if (cmd->argc < 2) {
793     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
794         "Usage: /KILL <nickname> [<comment>]");
795     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
796     goto out;
797   }
798
799   /* Parse the typed nickname. */
800   if (client->internal->params->nickname_parse)
801     client->internal->params->nickname_parse(cmd->argv[1], &nickname);
802   else
803     nickname = strdup(cmd->argv[1]);
804
805   /* Get the target client */
806   target = silc_idlist_get_client(cmd->client, conn, nickname, 
807                                   cmd->argv[1], TRUE);
808   if (!target) {
809     if (cmd->pending) {
810       COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
811       goto out;
812     }
813
814     /* Client entry not found, it was requested thus mark this to be
815        pending command. */
816     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
817                                 conn->cmd_ident,  
818                                 silc_client_command_kill, 
819                                 silc_client_command_dup(cmd));
820     cmd->pending = 1;
821     goto out;
822   }
823
824   /* Send the KILL command to the server */
825   idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
826   if (cmd->argc == 2)
827     buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 
828                                             ++conn->cmd_ident, 1, 
829                                             1, idp->data, idp->len);
830   else
831     buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 
832                                             ++conn->cmd_ident, 2, 
833                                             1, idp->data, idp->len,
834                                             2, cmd->argv[2], 
835                                             strlen(cmd->argv[2]));
836   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
837                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
838   silc_buffer_free(buffer);
839   silc_buffer_free(idp);
840
841   /* Notify application */
842   COMMAND(SILC_STATUS_OK);
843
844   /* Register a pending callback that will actually remove the killed
845      client from our cache. */
846   silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
847                               silc_client_command_kill_remove,
848                               silc_client_command_dup(cmd));
849
850  out:
851   silc_free(nickname);
852   silc_client_command_free(cmd);
853 }
854
855 /* Command INFO. Request information about specific server. If specific
856    server is not provided the current server is used. */
857
858 SILC_CLIENT_CMD_FUNC(info)
859 {
860   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
861   SilcClientConnection conn = cmd->conn;
862   SilcBuffer buffer;
863   char *name = NULL;
864
865   if (!cmd->conn) {
866     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
867     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
868     goto out;
869   }
870
871   if (cmd->argc == 2)
872     name = strdup(cmd->argv[1]);
873
874   /* Send the command */
875   if (name)
876     buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, 
877                                             1, name, strlen(name));
878   else
879     buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
880                                          NULL, NULL, NULL, 0);
881   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
882                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
883   silc_buffer_free(buffer);
884   if (name)
885     silc_free(name);
886
887   /* Notify application */
888   COMMAND(SILC_STATUS_OK);
889
890  out:
891   silc_client_command_free(cmd);
892 }
893
894 /* Command PING. Sends ping to server. This is used to test the 
895    communication channel. */
896
897 SILC_CLIENT_CMD_FUNC(ping)
898 {
899   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900   SilcClientConnection conn = cmd->conn;
901   SilcBuffer buffer;
902   void *id;
903   int i;
904
905   if (!cmd->conn) {
906     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
907     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
908     goto out;
909   }
910
911   /* Send the command */
912   buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
913                                           1, conn->remote_id_data, 
914                                           silc_id_get_len(conn->remote_id,
915                                                           SILC_ID_SERVER));
916   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
917                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
918   silc_buffer_free(buffer);
919
920   id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
921                       SILC_ID_SERVER);
922   if (!id) {
923     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
924     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
925     goto out;
926   }
927
928   /* Start counting time */
929   for (i = 0; i < conn->ping_count; i++) {
930     if (conn->ping[i].dest_id == NULL) {
931       conn->ping[i].start_time = time(NULL);
932       conn->ping[i].dest_id = id;
933       conn->ping[i].dest_name = strdup(conn->remote_host);
934       break;
935     }
936   }
937   if (i >= conn->ping_count) {
938     i = conn->ping_count;
939     conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
940     conn->ping[i].start_time = time(NULL);
941     conn->ping[i].dest_id = id;
942     conn->ping[i].dest_name = strdup(conn->remote_host);
943     conn->ping_count++;
944   }
945   
946   /* Notify application */
947   COMMAND(SILC_STATUS_OK);
948
949  out:
950   silc_client_command_free(cmd);
951 }
952
953 /* Command JOIN. Joins to a channel. */
954
955 SILC_CLIENT_CMD_FUNC(join)
956 {
957   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
958   SilcClientConnection conn = cmd->conn;
959   SilcChannelEntry channel;
960   SilcBuffer buffer, idp, auth = NULL;
961   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
962   int i, passphrase_len = 0;
963
964   if (!cmd->conn) {
965     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
966     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
967     goto out;
968   }
969
970   if (cmd->argc < 2) {
971     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
972     goto out;
973   }
974   
975   /* See if we have joined to the requested channel already */
976   channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
977   if (channel && silc_client_on_channel(channel, conn->local_entry))
978     goto out;
979
980   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
981
982   if (cmd->argv_lens[1] > 256)
983     cmd->argv_lens[1] = 256;
984
985   name = cmd->argv[1];
986
987   for (i = 2; i < cmd->argc; i++) {
988     if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
989       cipher = cmd->argv[i + 1];
990       i++;
991     } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
992       hmac = cmd->argv[i + 1];
993       i++;
994     } else if (!strcasecmp(cmd->argv[i], "-founder") && cmd->argc > i + 1) {
995       if (!strcasecmp(cmd->argv[i + 1], "-pubkey")) {
996         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
997                                                   cmd->client->private_key,
998                                                   cmd->client->rng, conn->hash,
999                                                   conn->local_id,
1000                                                   SILC_ID_CLIENT);
1001       } else {
1002         auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1003                                         cmd->argv[i + 1], 
1004                                         cmd->argv_lens[i + 1]);
1005       }
1006       i++;
1007     } else {
1008       /* Passphrases must be UTF-8 encoded, so encode if it is not */
1009       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
1010         passphrase_len = silc_utf8_encoded_len(cmd->argv[i], 
1011                                                cmd->argv_lens[i], 0);
1012         pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
1013         passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
1014                                           0, pu8, passphrase_len);
1015         passphrase = pu8;
1016       } else {
1017         passphrase = strdup(cmd->argv[i]);
1018         passphrase_len = cmd->argv_lens[i];
1019       }
1020     }
1021   }
1022
1023   /* Send JOIN command to the server */
1024   buffer =
1025     silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
1026                                    1, name, strlen(name),
1027                                    2, idp->data, idp->len,
1028                                    3, passphrase, passphrase_len,
1029                                    4, cipher, cipher ? strlen(cipher) : 0,
1030                                    5, hmac, hmac ? strlen(hmac) : 0,
1031                                    6, auth ? auth->data : NULL,
1032                                    auth ? auth->len : 0);
1033   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1034                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1035   silc_buffer_free(buffer);
1036   silc_buffer_free(idp);
1037   if (auth)
1038     silc_buffer_free(auth);
1039   silc_free(passphrase);
1040
1041   /* Notify application */
1042   COMMAND(SILC_STATUS_OK);
1043
1044  out:
1045   silc_client_command_free(cmd);
1046 }
1047
1048 /* MOTD command. Requests motd from server. */
1049
1050 SILC_CLIENT_CMD_FUNC(motd)
1051 {
1052   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1053   SilcClientConnection conn = cmd->conn;
1054   SilcBuffer buffer;
1055
1056   if (!cmd->conn) {
1057     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1058     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1059     goto out;
1060   }
1061
1062   if (cmd->argc < 1 || cmd->argc > 2) {
1063     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1064         "Usage: /MOTD [<server>]");
1065     COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
1066                    SILC_STATUS_ERR_TOO_MANY_PARAMS));
1067     goto out;
1068   }
1069
1070   /* Send TOPIC command to the server */
1071   if (cmd->argc == 1)
1072     buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
1073                                             1, conn->remote_host, 
1074                                             strlen(conn->remote_host));
1075   else
1076     buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
1077                                             1, cmd->argv[1], 
1078                                             cmd->argv_lens[1]);
1079   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1080                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1081   silc_buffer_free(buffer);
1082
1083   /* Notify application */
1084   COMMAND(SILC_STATUS_OK);
1085
1086  out:
1087   silc_client_command_free(cmd);
1088 }
1089
1090 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1091    modes as client cannot set itself server/router operator privileges. */
1092
1093 SILC_CLIENT_CMD_FUNC(umode)
1094 {
1095   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1096   SilcClientConnection conn = cmd->conn;
1097   SilcBuffer buffer, idp;
1098   unsigned char *cp, modebuf[4];
1099   SilcUInt32 mode, add, len;
1100   int i;
1101
1102   if (!cmd->conn) {
1103     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1104     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1105     goto out;
1106   }
1107
1108   if (cmd->argc < 2) {
1109     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1110         "Usage: /UMODE +|-<modes>");
1111     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1112     goto out;
1113   }
1114
1115   mode = conn->local_entry->mode;
1116
1117   /* Are we adding or removing mode */
1118   if (cmd->argv[1][0] == '-')
1119     add = FALSE;
1120   else
1121     add = TRUE;
1122
1123   /* Parse mode */
1124   cp = cmd->argv[1] + 1;
1125   len = strlen(cp);
1126   for (i = 0; i < len; i++) {
1127     switch(cp[i]) {
1128     case 'a':
1129       if (add) {
1130         mode = 0;
1131         mode |= SILC_UMODE_SERVER_OPERATOR;
1132         mode |= SILC_UMODE_ROUTER_OPERATOR;
1133         mode |= SILC_UMODE_GONE;
1134         mode |= SILC_UMODE_INDISPOSED;
1135         mode |= SILC_UMODE_BUSY;
1136         mode |= SILC_UMODE_PAGE;
1137         mode |= SILC_UMODE_HYPER;
1138         mode |= SILC_UMODE_ROBOT;
1139         mode |= SILC_UMODE_BLOCK_PRIVMSG;
1140         mode |= SILC_UMODE_REJECT_WATCHING;
1141       } else {
1142         mode = SILC_UMODE_NONE;
1143       }
1144       break;
1145     case 's':
1146       if (add)
1147         mode |= SILC_UMODE_SERVER_OPERATOR;
1148       else
1149         mode &= ~SILC_UMODE_SERVER_OPERATOR;
1150       break;
1151     case 'r':
1152       if (add)
1153         mode |= SILC_UMODE_ROUTER_OPERATOR;
1154       else
1155         mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1156       break;
1157     case 'g':
1158       if (add)
1159         mode |= SILC_UMODE_GONE;
1160       else
1161         mode &= ~SILC_UMODE_GONE;
1162       break;
1163     case 'i':
1164       if (add)
1165         mode |= SILC_UMODE_INDISPOSED;
1166       else
1167         mode &= ~SILC_UMODE_INDISPOSED;
1168       break;
1169     case 'b':
1170       if (add)
1171         mode |= SILC_UMODE_BUSY;
1172       else
1173         mode &= ~SILC_UMODE_BUSY;
1174       break;
1175     case 'p':
1176       if (add)
1177         mode |= SILC_UMODE_PAGE;
1178       else
1179         mode &= ~SILC_UMODE_PAGE;
1180       break;
1181     case 'h':
1182       if (add)
1183         mode |= SILC_UMODE_HYPER;
1184       else
1185         mode &= ~SILC_UMODE_HYPER;
1186       break;
1187     case 't':
1188       if (add)
1189         mode |= SILC_UMODE_ROBOT;
1190       else
1191         mode &= ~SILC_UMODE_ROBOT;
1192       break;
1193     case 'P':
1194       if (add)
1195         mode |= SILC_UMODE_BLOCK_PRIVMSG;
1196       else
1197         mode &= ~SILC_UMODE_BLOCK_PRIVMSG;
1198       break;
1199     case 'w':
1200       if (add)
1201         mode |= SILC_UMODE_REJECT_WATCHING;
1202       else
1203         mode &= ~SILC_UMODE_REJECT_WATCHING;
1204       break;
1205     case 'I':
1206       if (add)
1207         mode |= SILC_UMODE_BLOCK_INVITE;
1208       else
1209         mode &= ~SILC_UMODE_BLOCK_INVITE;
1210       break;
1211     default:
1212       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1213       goto out;
1214       break;
1215     }
1216   }
1217
1218   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1219   SILC_PUT32_MSB(mode, modebuf);
1220
1221   /* Send the command packet. We support sending only one mode at once
1222      that requires an argument. */
1223   buffer = 
1224     silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, 
1225                                    1, idp->data, idp->len, 
1226                                    2, modebuf, sizeof(modebuf));
1227   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1228                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1229   silc_buffer_free(buffer);
1230   silc_buffer_free(idp);
1231
1232   /* Notify application */
1233   COMMAND(SILC_STATUS_OK);
1234
1235  out:
1236   silc_client_command_free(cmd);
1237 }
1238
1239 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1240    can be set several at once. Those modes that require argument must be set
1241    separately (unless set with modes that does not require arguments). */
1242
1243 SILC_CLIENT_CMD_FUNC(cmode)
1244 {
1245   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1246   SilcClientConnection conn = cmd->conn;
1247   SilcChannelEntry channel;
1248   SilcBuffer buffer, chidp, auth = NULL;
1249   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1250   SilcUInt32 mode, add, type, len, arg_len = 0;
1251   int i;
1252
1253   if (!cmd->conn) {
1254     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1255     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1256     goto out;
1257   }
1258
1259   if (cmd->argc < 3) {
1260     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1261         "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1262     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1263     goto out;
1264   }
1265
1266   if (cmd->argv[1][0] == '*') {
1267     if (!conn->current_channel) {
1268       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1269           "You are not on any channel");
1270       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1271       goto out;
1272     }
1273
1274     channel = conn->current_channel;
1275   } else {
1276     name = cmd->argv[1];
1277
1278     channel = silc_client_get_channel(cmd->client, conn, name);
1279     if (!channel) {
1280       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1281           "You are on that channel");
1282       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1283       goto out;
1284     }
1285   }
1286
1287   mode = channel->mode;
1288
1289   /* Are we adding or removing mode */
1290   if (cmd->argv[2][0] == '-')
1291     add = FALSE;
1292   else
1293     add = TRUE;
1294
1295   /* Argument type to be sent to server */
1296   type = 0;
1297
1298   /* Parse mode */
1299   cp = cmd->argv[2] + 1;
1300   len = strlen(cp);
1301   for (i = 0; i < len; i++) {
1302     switch(cp[i]) {
1303     case 'p':
1304       if (add)
1305         mode |= SILC_CHANNEL_MODE_PRIVATE;
1306       else
1307         mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1308       break;
1309     case 's':
1310       if (add)
1311         mode |= SILC_CHANNEL_MODE_SECRET;
1312       else
1313         mode &= ~SILC_CHANNEL_MODE_SECRET;
1314       break;
1315     case 'k':
1316       if (add)
1317         mode |= SILC_CHANNEL_MODE_PRIVKEY;
1318       else
1319         mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1320       break;
1321     case 'i':
1322       if (add)
1323         mode |= SILC_CHANNEL_MODE_INVITE;
1324       else
1325         mode &= ~SILC_CHANNEL_MODE_INVITE;
1326       break;
1327     case 't':
1328       if (add)
1329         mode |= SILC_CHANNEL_MODE_TOPIC;
1330       else
1331         mode &= ~SILC_CHANNEL_MODE_TOPIC;
1332       break;
1333     case 'm':
1334       if (add)
1335         mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
1336       else
1337         mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
1338       break;
1339     case 'M':
1340       if (add)
1341         mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
1342       else
1343         mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
1344       break;
1345     case 'l':
1346       if (add) {
1347         int ll;
1348         mode |= SILC_CHANNEL_MODE_ULIMIT;
1349         type = 3;
1350         if (cmd->argc < 4) {
1351           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1352               "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1353           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1354           goto out;
1355         }
1356         ll = atoi(cmd->argv[3]);
1357         SILC_PUT32_MSB(ll, tmp);
1358         arg = tmp;
1359         arg_len = 4;
1360       } else {
1361         mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1362       }
1363       break;
1364     case 'a':
1365       if (add) {
1366         mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1367         type = 4;
1368         if (cmd->argc < 4) {
1369           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1370               "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1371           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1372           goto out;
1373         }
1374         arg = cmd->argv[3];
1375         arg_len = cmd->argv_lens[3];
1376       } else {
1377         mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1378       }
1379       break;
1380     case 'c':
1381       if (add) {
1382         mode |= SILC_CHANNEL_MODE_CIPHER;
1383         type = 5;
1384         if (cmd->argc < 4) {
1385           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1386               "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1387           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1388           goto out;
1389         }
1390         arg = cmd->argv[3];
1391         arg_len = cmd->argv_lens[3];
1392       } else {
1393         mode &= ~SILC_CHANNEL_MODE_CIPHER;
1394       }
1395       break;
1396     case 'h':
1397       if (add) {
1398         mode |= SILC_CHANNEL_MODE_HMAC;
1399         type = 6;
1400         if (cmd->argc < 4) {
1401           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1402               "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1403           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1404           goto out;
1405         }
1406         arg = cmd->argv[3];
1407         arg_len = cmd->argv_lens[3];
1408       } else {
1409         mode &= ~SILC_CHANNEL_MODE_HMAC;
1410       }
1411       break;
1412     case 'f':
1413       if (add) {
1414         mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
1415         type = 7;
1416
1417         if (cmd->argc < 4) {
1418           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1419               "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1420           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1421           goto out;
1422         }
1423
1424         if (!strcasecmp(cmd->argv[3], "-pubkey")) {
1425           auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1426                                                     cmd->client->private_key,
1427                                                     cmd->client->rng, 
1428                                                     conn->hash,
1429                                                     conn->local_id,
1430                                                     SILC_ID_CLIENT);
1431         } else {
1432           auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1433                                           cmd->argv[3], cmd->argv_lens[3]);
1434         }
1435
1436         arg = auth->data;
1437         arg_len = auth->len;
1438       } else {
1439         mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
1440       }
1441       break;
1442     default:
1443       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1444       goto out;
1445       break;
1446     }
1447   }
1448
1449   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1450   SILC_PUT32_MSB(mode, modebuf);
1451
1452   /* Send the command packet. We support sending only one mode at once
1453      that requires an argument. */
1454   if (type && arg) {
1455     buffer = 
1456       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
1457                                      1, chidp->data, chidp->len, 
1458                                      2, modebuf, sizeof(modebuf),
1459                                      type, arg, arg_len);
1460   } else {
1461     buffer = 
1462       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
1463                                      1, chidp->data, chidp->len, 
1464                                      2, modebuf, sizeof(modebuf));
1465   }
1466
1467   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1468                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1469   silc_buffer_free(buffer);
1470   silc_buffer_free(chidp);
1471   if (auth)
1472     silc_buffer_free(auth);
1473
1474   /* Notify application */
1475   COMMAND(SILC_STATUS_OK);
1476
1477  out:
1478   silc_client_command_free(cmd);
1479 }
1480
1481 /* CUMODE command. Changes client's mode on a channel. */
1482
1483 SILC_CLIENT_CMD_FUNC(cumode)
1484 {
1485   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1486   SilcClient client = cmd->client;
1487   SilcClientConnection conn = cmd->conn;
1488   SilcChannelEntry channel;
1489   SilcChannelUser chu;
1490   SilcClientEntry client_entry;
1491   SilcBuffer buffer, clidp, chidp, auth = NULL;
1492   unsigned char *name, *cp, modebuf[4];
1493   SilcUInt32 mode = 0, add, len;
1494   char *nickname = NULL;
1495   int i;
1496
1497   if (!cmd->conn) {
1498     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1499     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1500     goto out;
1501   }
1502
1503   if (cmd->argc < 4) {
1504     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1505         "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1506     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1507     goto out;
1508   }
1509
1510   if (cmd->argv[1][0] == '*') {
1511     if (!conn->current_channel) {
1512       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1513           "You are not on any channel");
1514       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1515       goto out;
1516     }
1517
1518     channel = conn->current_channel;
1519   } else {
1520     name = cmd->argv[1];
1521
1522     channel = silc_client_get_channel(cmd->client, conn, name);
1523     if (!channel) {
1524       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1525           "You are on that channel");
1526       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1527       goto out;
1528     }
1529   }
1530
1531   /* Parse the typed nickname. */
1532   if (client->internal->params->nickname_parse)
1533     client->internal->params->nickname_parse(cmd->argv[3], &nickname);
1534   else
1535     nickname = strdup(cmd->argv[3]);
1536
1537   /* Find client entry */
1538   client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
1539                                         cmd->argv[3], TRUE);
1540   if (!client_entry) {
1541     if (cmd->pending) {
1542       COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1543       goto out;
1544     }
1545
1546     /* Client entry not found, it was requested thus mark this to be
1547        pending command. */
1548     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
1549                                 conn->cmd_ident,  
1550                                 silc_client_command_cumode, 
1551                                 silc_client_command_dup(cmd));
1552     cmd->pending = 1;
1553     goto out;
1554   }
1555   
1556   /* Get the current mode */
1557   chu = silc_client_on_channel(channel, client_entry);
1558   if (chu)
1559     mode = chu->mode;
1560
1561   /* Are we adding or removing mode */
1562   if (cmd->argv[2][0] == '-')
1563     add = FALSE;
1564   else
1565     add = TRUE;
1566
1567   /* Parse mode */
1568   cp = cmd->argv[2] + 1;
1569   len = strlen(cp);
1570   for (i = 0; i < len; i++) {
1571     switch(cp[i]) {
1572     case 'a':
1573       if (add) {
1574         mode |= SILC_CHANNEL_UMODE_CHANFO;
1575         mode |= SILC_CHANNEL_UMODE_CHANOP;
1576         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1577         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1578         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1579       } else {
1580         mode = SILC_CHANNEL_UMODE_NONE;
1581       }
1582       break;
1583     case 'f':
1584       if (add) {
1585         if (cmd->argc == 5) {
1586           if (!strcasecmp(cmd->argv[4], "-pubkey")) {
1587             auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1588                                                       cmd->client->private_key,
1589                                                       cmd->client->rng,
1590                                                       conn->hash,
1591                                                       conn->local_id,
1592                                                       SILC_ID_CLIENT);
1593           } else {
1594             auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1595                                             cmd->argv[4], cmd->argv_lens[4]);
1596           }
1597         }
1598         mode |= SILC_CHANNEL_UMODE_CHANFO;
1599       } else {
1600         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1601       }
1602       break;
1603     case 'o':
1604       if (add)
1605         mode |= SILC_CHANNEL_UMODE_CHANOP;
1606       else
1607         mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1608       break;
1609     case 'b':
1610       if (add)
1611         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1612       else
1613         mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
1614       break;
1615     case 'u':
1616       if (add)
1617         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1618       else
1619         mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
1620       break;
1621     case 'r':
1622       if (add)
1623         mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1624       else
1625         mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
1626       break;
1627     default:
1628       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
1629       goto out;
1630       break;
1631     }
1632   }
1633
1634   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1635   SILC_PUT32_MSB(mode, modebuf);
1636   clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1637
1638   /* Send the command packet. We support sending only one mode at once
1639      that requires an argument. */
1640   buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 
1641                                           auth ? 4 : 3, 
1642                                           1, chidp->data, chidp->len, 
1643                                           2, modebuf, 4,
1644                                           3, clidp->data, clidp->len,
1645                                           4, auth ? auth->data : NULL, 
1646                                           auth ? auth->len : 0);
1647   
1648   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1649                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1650   silc_buffer_free(buffer);
1651   silc_buffer_free(chidp);
1652   silc_buffer_free(clidp);
1653   if (auth)
1654     silc_buffer_free(auth);
1655   
1656   /* Notify application */
1657   COMMAND(SILC_STATUS_OK);
1658
1659  out:
1660   silc_free(nickname);
1661   silc_client_command_free(cmd);
1662 }
1663
1664 /* KICK command. Kicks a client out of channel. */
1665
1666 SILC_CLIENT_CMD_FUNC(kick)
1667 {
1668   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1669   SilcClient client = cmd->client;
1670   SilcClientConnection conn = cmd->conn;
1671   SilcIDCacheEntry id_cache = NULL;
1672   SilcChannelEntry channel;
1673   SilcBuffer buffer, idp, idp2;
1674   SilcClientEntry target;
1675   char *name;
1676   char *nickname = NULL;
1677
1678   if (!cmd->conn) {
1679     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1680     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1681     goto out;
1682   }
1683
1684   if (cmd->argc < 3) {
1685     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1686         "Usage: /KICK <channel> <nickname> [<comment>]");
1687     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1688     goto out;
1689   }
1690
1691   if (cmd->argv[1][0] == '*') {
1692     if (!conn->current_channel) {
1693       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1694           "You are not on any channel");
1695       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1696       goto out;
1697     }
1698     name = conn->current_channel->channel_name;
1699   } else {
1700     name = cmd->argv[1];
1701   }
1702
1703   if (!conn->current_channel) {
1704     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1705         "You are not on that channel");
1706     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1707     goto out;
1708   }
1709
1710   /* Get the Channel ID of the channel */
1711   if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
1712     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1713         "You are not on that channel");
1714     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1715     goto out;
1716   }
1717
1718   channel = (SilcChannelEntry)id_cache->context;
1719
1720   /* Parse the typed nickname. */
1721   if (client->internal->params->nickname_parse)
1722     client->internal->params->nickname_parse(cmd->argv[2], &nickname);
1723   else
1724     nickname = strdup(cmd->argv[2]);
1725
1726   /* Get the target client */
1727   target = silc_idlist_get_client(cmd->client, conn, nickname, 
1728                                   cmd->argv[2], FALSE);
1729   if (!target) {
1730     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1731         "No such client: %s", cmd->argv[2]);
1732     COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
1733     goto out;
1734   }
1735
1736   /* Send KICK command to the server */
1737   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1738   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1739   if (cmd->argc == 3)
1740     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
1741                                             1, idp->data, idp->len,
1742                                             2, idp2->data, idp2->len);
1743   else
1744     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
1745                                             1, idp->data, idp->len,
1746                                             2, idp2->data, idp2->len,
1747                                             3, cmd->argv[3], 
1748                                             strlen(cmd->argv[3]));
1749   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1750                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1751   silc_buffer_free(buffer);
1752   silc_buffer_free(idp);
1753   silc_buffer_free(idp2);
1754
1755   /* Notify application */
1756   COMMAND(SILC_STATUS_OK);
1757
1758  out:
1759   silc_free(nickname);
1760   silc_client_command_free(cmd);
1761 }
1762
1763 static void silc_client_command_oper_send(unsigned char *data,
1764                                           SilcUInt32 data_len, void *context)
1765 {
1766   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1767   SilcClientConnection conn = cmd->conn;
1768   SilcBuffer buffer, auth;
1769
1770   if (cmd->argc >= 3) {
1771     /* Encode the public key authentication payload */
1772     auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1773                                               cmd->client->private_key,
1774                                               cmd->client->rng, conn->hash,
1775                                               conn->local_id,
1776                                               SILC_ID_CLIENT);
1777   } else {
1778     /* Encode the password authentication payload */
1779     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1780                                     data, data_len);
1781   }
1782
1783   buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
1784                                           1, cmd->argv[1], 
1785                                           strlen(cmd->argv[1]),
1786                                           2, auth->data, auth->len);
1787   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1788                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1789
1790   silc_buffer_free(buffer);
1791   silc_buffer_free(auth);
1792
1793   /* Notify application */
1794   COMMAND(SILC_STATUS_OK);
1795 }
1796
1797 /* OPER command. Used to obtain server operator privileges. */
1798
1799 SILC_CLIENT_CMD_FUNC(oper)
1800 {
1801   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1802   SilcClientConnection conn = cmd->conn;
1803
1804   if (!cmd->conn) {
1805     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1806     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1807     goto out;
1808   }
1809
1810   if (cmd->argc < 2) {
1811     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1812         "Usage: /OPER <username> [-pubkey]");
1813     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1814     goto out;
1815   }
1816
1817   if (cmd->argc < 3) {
1818     /* Get passphrase */
1819     cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1820                                      silc_client_command_oper_send,
1821                                      context);
1822     return;
1823   }
1824
1825   silc_client_command_oper_send(NULL, 0, context);
1826
1827  out:
1828   silc_client_command_free(cmd);
1829 }
1830
1831 static void silc_client_command_silcoper_send(unsigned char *data,
1832                                               SilcUInt32 data_len, 
1833                                               void *context)
1834 {
1835   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1836   SilcClientConnection conn = cmd->conn;
1837   SilcBuffer buffer, auth;
1838
1839   if (cmd->argc >= 3) {
1840     /* Encode the public key authentication payload */
1841     auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
1842                                               cmd->client->private_key,
1843                                               cmd->client->rng, conn->hash,
1844                                               conn->local_id,
1845                                               SILC_ID_CLIENT);
1846   } else {
1847     /* Encode the password authentication payload */
1848     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1849                                     data, data_len);
1850   }
1851
1852   buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
1853                                           1, cmd->argv[1], 
1854                                           strlen(cmd->argv[1]),
1855                                           2, auth->data, auth->len);
1856   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1857                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1858
1859   silc_buffer_free(buffer);
1860   silc_buffer_free(auth);
1861
1862   /* Notify application */
1863   COMMAND(SILC_STATUS_OK);
1864 }
1865
1866 /* SILCOPER command. Used to obtain router operator privileges. */
1867
1868 SILC_CLIENT_CMD_FUNC(silcoper)
1869 {
1870   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1871   SilcClientConnection conn = cmd->conn;
1872
1873   if (!cmd->conn) {
1874     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1875     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1876     goto out;
1877   }
1878
1879   if (cmd->argc < 2) {
1880     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1881         "Usage: /SILCOPER <username> [-pubkey]");
1882     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1883     goto out;
1884   }
1885
1886   if (cmd->argc < 3) {
1887     /* Get passphrase */
1888     cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
1889                                      silc_client_command_silcoper_send,
1890                                      context);
1891     return;
1892   }
1893
1894   silc_client_command_silcoper_send(NULL, 0, context);
1895
1896  out:
1897   silc_client_command_free(cmd);
1898 }
1899
1900 /* Command BAN. This is used to manage the ban list of the channel. */
1901
1902 SILC_CLIENT_CMD_FUNC(ban)
1903 {
1904   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1905   SilcClientConnection conn = cmd->conn;
1906   SilcChannelEntry channel;
1907   SilcBuffer buffer, chidp;
1908   int type = 0;
1909   char *name, *ban = NULL;
1910
1911   if (!cmd->conn) {
1912     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1913     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1914     goto out;
1915   }
1916
1917   if (cmd->argc < 2) {
1918     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1919         "Usage: /BAN <channel> "
1920         "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
1921     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1922     goto out;
1923   }
1924
1925   if (cmd->argv[1][0] == '*') {
1926     if (!conn->current_channel) {
1927       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1928           "You are not on any channel");
1929       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1930       goto out;
1931     }
1932
1933     channel = conn->current_channel;
1934   } else {
1935     name = cmd->argv[1];
1936
1937     channel = silc_client_get_channel(cmd->client, conn, name);
1938     if (!channel) {
1939       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
1940           "You are noton that channel");
1941       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
1942       goto out;
1943     }
1944   }
1945
1946   if (cmd->argc == 3) {
1947     if (cmd->argv[2][0] == '+')
1948       type = 2;
1949     else
1950       type = 3;
1951
1952     ban = cmd->argv[2];
1953     ban++;
1954   }
1955
1956   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1957
1958   /* Send the command */
1959   buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 
1960                                           ++conn->cmd_ident, 2,
1961                                           1, chidp->data, chidp->len,
1962                                           type, ban, ban ? strlen(ban) : 0);
1963   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1964                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1965   silc_buffer_free(buffer);
1966   silc_buffer_free(chidp);
1967
1968   /* Notify application */
1969   COMMAND(SILC_STATUS_OK);
1970
1971  out:
1972   silc_client_command_free(cmd);
1973 }
1974
1975 /* Command DETACH. This is used to detach from the server */
1976
1977 SILC_CLIENT_CMD_FUNC(detach)
1978 {
1979   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1980   SilcClientConnection conn = cmd->conn;
1981   SilcBuffer buffer;
1982
1983   if (!cmd->conn) {
1984     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1985     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
1986     goto out;
1987   }
1988
1989   buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
1990                                           ++conn->cmd_ident, 0);
1991   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1992                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1993   silc_buffer_free(buffer);
1994
1995   /* Notify application */
1996   COMMAND(SILC_STATUS_OK);
1997
1998  out:
1999   silc_client_command_free(cmd);
2000 }
2001
2002 /* Command WATCH. */
2003
2004 SILC_CLIENT_CMD_FUNC(watch)
2005 {
2006   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2007   SilcClientConnection conn = cmd->conn;
2008   SilcBuffer buffer, idp = NULL;
2009   int type = 0;
2010
2011   if (!cmd->conn) {
2012     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2013     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2014     goto out;
2015   }
2016
2017   if (cmd->argc < 3) {
2018     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2019     goto out;
2020   }
2021
2022   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
2023
2024   if (!strcasecmp(cmd->argv[1], "-add")) {
2025     type = 2;
2026   } else if (!strcasecmp(cmd->argv[1], "-del")) {
2027     type = 3;
2028   } else {
2029     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2030     goto out;
2031   }
2032
2033   buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH, 
2034                                           ++conn->cmd_ident, 2,
2035                                           1, idp->data, idp->len,
2036                                           type, cmd->argv[2],
2037                                           cmd->argv_lens[2]);
2038   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
2039                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2040   silc_buffer_free(buffer);
2041
2042   /* Notify application */
2043   COMMAND(SILC_STATUS_OK);
2044
2045  out:
2046   if (idp)
2047     silc_buffer_free(idp);
2048   silc_client_command_free(cmd);
2049 }
2050
2051 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
2052
2053 SILC_CLIENT_CMD_FUNC(leave)
2054 {
2055   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2056   SilcClientConnection conn = cmd->conn;
2057   SilcChannelEntry channel;
2058   SilcChannelUser chu;
2059   SilcBuffer buffer, idp;
2060   char *name;
2061
2062   if (!cmd->conn) {
2063     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2064     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2065     goto out;
2066   }
2067
2068   if (cmd->argc != 2) {
2069     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2070         "Usage: /LEAVE <channel>");
2071     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2072     goto out;
2073   }
2074
2075   if (cmd->argv[1][0] == '*') {
2076     if (!conn->current_channel) {
2077       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2078           "You are not on any channel");
2079       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2080       goto out;
2081     }
2082     name = conn->current_channel->channel_name;
2083   } else {
2084     name = cmd->argv[1];
2085   }
2086
2087   /* Get the channel entry */
2088   channel = silc_client_get_channel(cmd->client, conn, name);
2089   if (!channel) {
2090     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2091         "You are not on that channel");
2092     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093     goto out;
2094   }
2095
2096   /* Remove us from channel */
2097   chu = silc_client_on_channel(channel, conn->local_entry);
2098   if (chu) {
2099     silc_hash_table_del(chu->client->channels, chu->channel);
2100     silc_hash_table_del(chu->channel->user_list, chu->client);
2101     silc_free(chu);
2102   }
2103
2104   /* Send LEAVE command to the server */
2105   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2106   buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
2107                                           1, idp->data, idp->len);
2108   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
2109                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2110   silc_buffer_free(buffer);
2111   silc_buffer_free(idp);
2112
2113   /* Notify application */
2114   COMMAND(SILC_STATUS_OK);
2115
2116   if (conn->current_channel == channel)
2117     conn->current_channel = NULL;
2118
2119   silc_client_del_channel(cmd->client, cmd->conn, channel);
2120
2121  out:
2122   silc_client_command_free(cmd);
2123 }
2124
2125 /* Command USERS. Requests the USERS of the clients joined on requested
2126    channel. */
2127
2128 SILC_CLIENT_CMD_FUNC(users)
2129 {
2130   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2131   SilcClientConnection conn = cmd->conn;
2132   SilcBuffer buffer;
2133   char *name;
2134
2135   if (!cmd->conn) {
2136     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2137     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2138     goto out;
2139   }
2140
2141   if (cmd->argc != 2) {
2142     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2143         "Usage: /USERS <channel>");
2144     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2145     goto out;
2146   }
2147
2148   if (cmd->argv[1][0] == '*') {
2149     if (!conn->current_channel) {
2150       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2151           "You are not on any channel");
2152       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
2153       goto out;
2154     }
2155     name = conn->current_channel->channel_name;
2156   } else {
2157     name = cmd->argv[1];
2158   }
2159
2160   /* Send USERS command to the server */
2161   buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 
2162                                           ++conn->cmd_ident, 1, 
2163                                           2, name, strlen(name));
2164   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
2165                           NULL, 0, NULL, NULL, buffer->data, 
2166                           buffer->len, TRUE);
2167   silc_buffer_free(buffer);
2168
2169   /* Notify application */
2170   COMMAND(SILC_STATUS_OK);
2171
2172  out:
2173   silc_client_command_free(cmd);
2174 }
2175
2176 /* Command GETKEY. Used to fetch remote client's public key. */
2177
2178 SILC_CLIENT_CMD_FUNC(getkey)
2179 {
2180   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2181   SilcClientConnection conn = cmd->conn;
2182   SilcClient client = cmd->client;
2183   SilcClientEntry client_entry = NULL;
2184   SilcServerEntry server_entry = NULL;
2185   char *nickname = NULL;
2186   SilcBuffer idp, buffer;
2187
2188   SILC_LOG_DEBUG(("Start"));
2189
2190   if (!cmd->conn) {
2191     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2192     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2193     goto out;
2194   }
2195
2196   if (cmd->argc < 2) {
2197     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, 
2198                      "Usage: /GETKEY <nickname or server name>");
2199     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2200     goto out;
2201   }
2202
2203   /* Parse the typed nickname. */
2204   if (client->internal->params->nickname_parse)
2205     client->internal->params->nickname_parse(cmd->argv[1], &nickname);
2206   else
2207     nickname = strdup(cmd->argv[1]);
2208
2209   /* Find client entry */
2210   client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
2211                                         FALSE);
2212   if (!client_entry) {
2213     /* Check whether user requested server actually */
2214     server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
2215
2216     if (!server_entry) {
2217       /* No. what ever user wants we don't have it, so resolve it. We
2218          will first try to resolve the client, and if that fails then
2219          we'll try to resolve the server. */
2220
2221       if (!cmd->pending) {
2222         /* This will send the IDENTIFY command for nickname */
2223         silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
2224         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
2225                                     conn->cmd_ident,  
2226                                     silc_client_command_getkey, 
2227                                     silc_client_command_dup(cmd));
2228         cmd->pending = 1;
2229         goto out;
2230       } else {
2231         SilcClientCommandReplyContext reply = 
2232           (SilcClientCommandReplyContext)context2;
2233         SilcStatus error;
2234
2235         /* If nickname was not found, then resolve the server. */
2236         silc_command_get_status(reply->payload, NULL, &error);
2237         if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
2238           /* This sends the IDENTIFY command to resolve the server. */
2239           silc_client_command_register(client, SILC_COMMAND_IDENTIFY, 
2240                                        NULL, NULL,
2241                                        silc_client_command_reply_identify_i, 0,
2242                                        ++conn->cmd_ident);
2243           silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
2244                                    conn->cmd_ident, 1, 
2245                                    2, cmd->argv[1], cmd->argv_lens[1]);
2246           silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
2247                                       conn->cmd_ident, 
2248                                       silc_client_command_getkey, 
2249                                       silc_client_command_dup(cmd));
2250           goto out;
2251         }
2252
2253         /* If server was not found, then we've resolved both nickname and
2254            server and did not find anybody. */
2255         if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
2256           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
2257              silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
2258           SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
2259            silc_get_status_message(error));
2260           COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
2261           goto out;
2262         }
2263
2264         COMMAND_ERROR(error);
2265         goto out;
2266       }
2267     }
2268
2269     idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
2270   } else {
2271     idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
2272   }
2273
2274   buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, 
2275                                           1, idp->data, idp->len);
2276   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
2277                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2278   silc_buffer_free(buffer);
2279   silc_buffer_free(idp);
2280
2281   /* Notify application */
2282   COMMAND(SILC_STATUS_OK);
2283
2284  out:
2285   silc_free(nickname);
2286   silc_client_command_free(cmd);
2287 }
2288
2289 /* Register a new command indicated by the `command' to the SILC client.
2290    The `name' is optional command name.  If provided the command may be
2291    searched using the silc_client_command_find by that name.  The
2292    `command_function' is the function to be called when the command is
2293    executed, and the `command_reply_function' is the function to be
2294    called after the server has sent reply back to the command. 
2295
2296    The `ident' is optional identifier for the command.  If non-zero
2297    the `command_reply_function' for the command type `command' will be
2298    called only if the command reply sent by server includes the 
2299    command identifier `ident'. Application usually does not need it
2300    and set it to zero value. */
2301
2302 bool silc_client_command_register(SilcClient client,
2303                                   SilcCommand command,
2304                                   const char *name,
2305                                   SilcCommandCb command_function,
2306                                   SilcCommandCb command_reply_function,
2307                                   SilcUInt8 max_args,
2308                                   SilcUInt16 ident)
2309 {
2310   SilcClientCommand cmd;
2311
2312   cmd = silc_calloc(1, sizeof(*cmd));
2313   cmd->cmd = command;
2314   cmd->command = command_function;
2315   cmd->reply = command_reply_function;
2316   cmd->name = name ? strdup(name) : NULL;
2317   cmd->max_args = max_args;
2318   cmd->ident = ident;
2319
2320   silc_list_add(client->internal->commands, cmd);
2321
2322   return TRUE;
2323 }
2324
2325 /* Unregister a command indicated by the `command' with command function
2326    `command_function' and command reply function `command_reply_function'.
2327    Returns TRUE if the command was found and unregistered. */
2328
2329 bool silc_client_command_unregister(SilcClient client,
2330                                     SilcCommand command,
2331                                     SilcCommandCb command_function,
2332                                     SilcCommandCb command_reply_function,
2333                                     SilcUInt16 ident)
2334 {
2335   SilcClientCommand cmd;
2336
2337   silc_list_start(client->internal->commands);
2338   while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
2339     if (cmd->cmd == command && cmd->command == command_function &&
2340         cmd->reply == command_reply_function && cmd->ident == ident) {
2341       silc_list_del(client->internal->commands, cmd);
2342       silc_free(cmd->name);
2343       silc_free(cmd);
2344       return TRUE;
2345     }
2346   }
2347
2348   return FALSE;
2349 }
2350
2351 /* Private range commands, specific to this implementation (and compatible
2352    with SILC Server). */
2353
2354 /* CONNECT command. Connects the server to another server. */
2355
2356 SILC_CLIENT_CMD_FUNC(connect)
2357 {
2358   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2359   SilcClientConnection conn = cmd->conn;
2360   SilcBuffer buffer;
2361   unsigned char port[4];
2362   SilcUInt32 tmp;
2363
2364   if (!cmd->conn) {
2365     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2366     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2367     goto out;
2368   }
2369
2370   if (cmd->argc < 2) {
2371     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2372         "Usage: /CONNECT <server> [<port>]");
2373     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2374     goto out;
2375   }
2376
2377   if (cmd->argc == 3) {
2378     tmp = atoi(cmd->argv[2]);
2379     SILC_PUT32_MSB(tmp, port);
2380   }
2381
2382   if (cmd->argc == 3)
2383     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2, 
2384                                             1, cmd->argv[1], 
2385                                             strlen(cmd->argv[1]),
2386                                             2, port, 4);
2387   else
2388     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
2389                                             1, cmd->argv[1], 
2390                                             strlen(cmd->argv[1]));
2391   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2392                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2393   silc_buffer_free(buffer);
2394
2395   /* Notify application */
2396   COMMAND(SILC_STATUS_OK);
2397
2398  out:
2399   silc_client_command_free(cmd);
2400 }
2401
2402
2403 /* CLOSE command. Close server connection to the remote server */
2404  
2405 SILC_CLIENT_CMD_FUNC(close)
2406 {
2407   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2408   SilcClientConnection conn = cmd->conn;
2409   SilcBuffer buffer;
2410   unsigned char port[4];
2411   SilcUInt32 tmp;
2412
2413   if (!cmd->conn) {
2414     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2415     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2416     goto out;
2417   }
2418
2419   if (cmd->argc < 2) {
2420     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
2421         "Usage: /CLOSE <server> [<port>]");
2422     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2423     goto out;
2424   }
2425
2426   if (cmd->argc == 3) {
2427     tmp = atoi(cmd->argv[2]);
2428     SILC_PUT32_MSB(tmp, port);
2429   }
2430
2431   if (cmd->argc == 3)
2432     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2, 
2433                                             1, cmd->argv[1], 
2434                                             strlen(cmd->argv[1]),
2435                                             2, port, 4);
2436   else
2437     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
2438                                             1, cmd->argv[1], 
2439                                             strlen(cmd->argv[1]));
2440   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
2441                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2442   silc_buffer_free(buffer);
2443
2444   /* Notify application */
2445   COMMAND(SILC_STATUS_OK);
2446
2447  out:
2448   silc_client_command_free(cmd);
2449 }
2450  
2451 /* SHUTDOWN command. Shutdowns the server. */
2452
2453 SILC_CLIENT_CMD_FUNC(shutdown)
2454 {
2455   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2456
2457   if (!cmd->conn) {
2458     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2459     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
2460     goto out;
2461   }
2462
2463   /* Send the command */
2464   silc_client_command_send(cmd->client, cmd->conn, 
2465                            SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
2466
2467   /* Notify application */
2468   COMMAND(SILC_STATUS_OK);
2469
2470  out:
2471   silc_client_command_free(cmd);
2472 }
2473
2474 /* Register all default commands provided by the client library for the
2475    application. */
2476
2477 void silc_client_commands_register(SilcClient client)
2478 {
2479   silc_list_init(client->internal->commands, struct SilcClientCommandStruct, 
2480                  next);
2481
2482   SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
2483   SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
2484   SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
2485   SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
2486   SILC_CLIENT_CMD(list, LIST, "LIST", 2);
2487   SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
2488   SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
2489   SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
2490   SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
2491   SILC_CLIENT_CMD(info, INFO, "INFO", 2);
2492   SILC_CLIENT_CMD(ping, PING, "PING", 2);
2493   SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
2494   SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
2495   SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
2496   SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
2497   SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 4);
2498   SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
2499   SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
2500   SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
2501   SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
2502   SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
2503   SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
2504   SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
2505   SILC_CLIENT_CMD(users, USERS, "USERS", 2);
2506   SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
2507
2508   SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
2509   SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
2510   SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
2511 }
2512
2513 /* Unregister all commands. */
2514
2515 void silc_client_commands_unregister(SilcClient client)
2516 {
2517   SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
2518   SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
2519   SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
2520   SILC_CLIENT_CMDU(nick, NICK, "NICK");
2521   SILC_CLIENT_CMDU(list, LIST, "LIST");
2522   SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
2523   SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
2524   SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
2525   SILC_CLIENT_CMDU(kill, KILL, "KILL");
2526   SILC_CLIENT_CMDU(info, INFO, "INFO");
2527   SILC_CLIENT_CMDU(ping, PING, "PING");
2528   SILC_CLIENT_CMDU(oper, OPER, "OPER");
2529   SILC_CLIENT_CMDU(join, JOIN, "JOIN");
2530   SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
2531   SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
2532   SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
2533   SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
2534   SILC_CLIENT_CMDU(kick, KICK, "KICK");
2535   SILC_CLIENT_CMDU(ban, BAN, "BAN");
2536   SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
2537   SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
2538   SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
2539   SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
2540   SILC_CLIENT_CMDU(users, USERS, "USERS");
2541   SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
2542
2543   SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
2544   SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
2545   SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
2546 }