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