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