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