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