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