updates.
[silc.git] / lib / silcclient / command.c
1 /*
2
3   command.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
24
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
27 {
28   SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29   SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30   SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 
31                   SILC_CF_LAG | SILC_CF_REG, 3),
32   SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33   SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34   SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35   SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36   SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37   SILC_CLIENT_CMD(kill, KILL, "KILL", 
38                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39   SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40   SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42   SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43   SILC_CLIENT_CMD(oper, OPER, "OPER",
44                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45   SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46   SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47   SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48   SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49   SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50   SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51   SILC_CLIENT_CMD(restart, RESTART, "RESTART",
52                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
53   SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
54                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
55   SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
56                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
57   SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
58                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
59   SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
60   SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
61   SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
62
63   { NULL, 0, NULL, 0, 0 },
64 };
65
66 #define SILC_NOT_CONNECTED(x, c) \
67   x->ops->say((x), (c), \
68            "You are not connected to a server, use /SERVER to connect");
69
70 /* Command operation that is called at the end of all commands. 
71    Usage: COMMAND; */
72 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
73   cmd, TRUE, cmd->command->cmd)
74
75 /* Error to application. Usage: COMMAND_ERROR; */
76 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
77   cmd, FALSE, cmd->command->cmd)
78
79 /* Generic function to send any command. The arguments must be sent already
80    encoded into correct form and in correct order. */
81
82 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
83                               SilcCommand command, unsigned short ident,
84                               unsigned int argc, ...)
85 {
86   SilcBuffer packet;
87   va_list ap;
88
89   va_start(ap, argc);
90
91   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
92   silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
93                           NULL, 0, NULL, NULL, packet->data, 
94                           packet->len, TRUE);
95   silc_buffer_free(packet);
96 }
97
98 /* Finds and returns a pointer to the command list. Return NULL if the
99    command is not found. */
100
101 SilcClientCommand *silc_client_command_find(const char *name)
102 {
103   SilcClientCommand *cmd;
104
105   for (cmd = silc_command_list; cmd->name; cmd++) {
106     if (!strcmp(cmd->name, name))
107       return cmd;
108   }
109
110   return NULL;
111 }
112
113 /* Add new pending command to be executed when reply to a command has been
114    received.  The `reply_cmd' is the command that will call the `callback'
115    with `context' when reply has been received.  If `ident is non-zero
116    the `callback' will be executed when received reply with command 
117    identifier `ident'. */
118
119 void silc_client_command_pending(SilcClientConnection conn,
120                                  SilcCommand reply_cmd,
121                                  unsigned short ident,
122                                  SilcClientPendingDestructor destructor,
123                                  SilcCommandCb callback,
124                                  void *context)
125 {
126   SilcClientCommandPending *reply;
127
128   reply = silc_calloc(1, sizeof(*reply));
129   reply->reply_cmd = reply_cmd;
130   reply->ident = ident;
131   reply->context = context;
132   reply->callback = callback;
133   reply->destructor = destructor;
134   silc_dlist_add(conn->pending_commands, reply);
135 }
136
137 /* Deletes pending command by reply command type. */
138
139 void silc_client_command_pending_del(SilcClientConnection conn,
140                                      SilcCommand reply_cmd,
141                                      unsigned short ident)
142 {
143   SilcClientCommandPending *r;
144
145   silc_dlist_start(conn->pending_commands);
146   while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
147     if (r->reply_cmd == reply_cmd && r->ident == ident) {
148       silc_dlist_del(conn->pending_commands, r);
149       break;
150     }
151   }
152 }
153
154 /* Checks for pending commands and marks callbacks to be called from
155    the command reply function. Returns TRUE if there were pending command. */
156
157 int silc_client_command_pending_check(SilcClientConnection conn,
158                                       SilcClientCommandReplyContext ctx,
159                                       SilcCommand command, 
160                                       unsigned short ident)
161 {
162   SilcClientCommandPending *r;
163
164   silc_dlist_start(conn->pending_commands);
165   while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
166     if (r->reply_cmd == command && r->ident == ident) {
167       ctx->context = r->context;
168       ctx->callback = r->callback;
169       ctx->destructor = r->destructor;
170       ctx->ident = ident;
171       return TRUE;
172     }
173   }
174
175   return FALSE;
176 }
177
178 /* Allocate Command Context */
179
180 SilcClientCommandContext silc_client_command_alloc()
181 {
182   SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
183   ctx->users++;
184   return ctx;
185 }
186
187 /* Free command context and its internals */
188
189 void silc_client_command_free(SilcClientCommandContext ctx)
190 {
191   ctx->users--;
192   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193                   ctx->users));
194   if (ctx->users < 1) {
195     int i;
196
197     for (i = 0; i < ctx->argc; i++)
198       silc_free(ctx->argv[i]);
199     silc_free(ctx);
200   }
201 }
202
203 /* Duplicate Command Context by adding reference counter. The context won't
204    be free'd untill it hits zero. */
205
206 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
207 {
208   ctx->users++;
209   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
210                   ctx->users));
211   return ctx;
212 }
213
214 /* Pending command destructor. */
215
216 static void silc_client_command_destructor(void *context)
217 {
218   silc_client_command_free((SilcClientCommandContext)context);
219 }
220
221 /* silc_client_get_client completion callback */
222 void silc_client_command_completion(SilcClient client,
223                                     SilcClientConnection conn,
224                                     SilcClientEntry clients,
225                                     unsigned int clients_count,
226                                     void *context)
227 {
228
229 }
230
231 /* Command WHOIS. This command is used to query information about 
232    specific user. */
233
234 SILC_CLIENT_CMD_FUNC(whois)
235 {
236   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237   SilcClientConnection conn = cmd->conn;
238   SilcBuffer buffer;
239
240   if (!cmd->conn) {
241     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
242     COMMAND_ERROR;
243     goto out;
244   }
245
246   if (cmd->argc < 2 || cmd->argc > 3) {
247     cmd->client->ops->say(cmd->client, conn, 
248              "Usage: /WHOIS <nickname>[@<server>] [<count>]");
249     COMMAND_ERROR;
250     goto out;
251   }
252
253   buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
254                                        cmd->argc - 1, ++cmd->argv,
255                                        ++cmd->argv_lens, ++cmd->argv_types,
256                                        0);
257   silc_client_packet_send(cmd->client, cmd->conn->sock,
258                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
259                           buffer->data, buffer->len, TRUE);
260   silc_buffer_free(buffer);
261   cmd->argv--;
262   cmd->argv_lens--;
263   cmd->argv_types--;
264
265   /* Notify application */
266   COMMAND;
267
268  out:
269   silc_client_command_free(cmd);
270 }
271
272 /* Command WHOWAS. This command is used to query history information about
273    specific user that used to exist in the network. */
274
275 SILC_CLIENT_CMD_FUNC(whowas)
276 {
277   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
278   SilcClientConnection conn = cmd->conn;
279   SilcBuffer buffer;
280
281   if (!cmd->conn) {
282     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
283     COMMAND_ERROR;
284     goto out;
285   }
286
287   if (cmd->argc < 2 || cmd->argc > 3) {
288     cmd->client->ops->say(cmd->client, conn, 
289              "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
290     COMMAND_ERROR;
291     goto out;
292   }
293
294   buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
295                                        cmd->argc - 1, ++cmd->argv,
296                                        ++cmd->argv_lens, ++cmd->argv_types,
297                                        0);
298   silc_client_packet_send(cmd->client, cmd->conn->sock,
299                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
300                           buffer->data, buffer->len, TRUE);
301   silc_buffer_free(buffer);
302   cmd->argv--;
303   cmd->argv_lens--;
304   cmd->argv_types--;
305
306   /* Notify application */
307   COMMAND;
308
309  out:
310   silc_client_command_free(cmd);
311 }
312
313 /* Command IDENTIFY. This command is used to query information about 
314    specific user, especially ID's. */
315
316 SILC_CLIENT_CMD_FUNC(identify)
317 {
318   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
319   SilcClientConnection conn = cmd->conn;
320   SilcBuffer buffer;
321
322   if (!cmd->conn) {
323     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
324     COMMAND_ERROR;
325     goto out;
326   }
327
328   if (cmd->argc < 2 || cmd->argc > 3) {
329     cmd->client->ops->say(cmd->client, conn,
330              "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
331     COMMAND_ERROR;
332     goto out;
333   }
334
335   buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
336                                        cmd->argc - 1, ++cmd->argv,
337                                        ++cmd->argv_lens, ++cmd->argv_types,
338                                        ++conn->cmd_ident);
339   silc_client_packet_send(cmd->client, cmd->conn->sock,
340                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
341                           buffer->data, buffer->len, TRUE);
342   silc_buffer_free(buffer);
343   cmd->argv--;
344   cmd->argv_lens--;
345   cmd->argv_types--;
346
347   /* Notify application */
348   COMMAND;
349
350  out:
351   silc_client_command_free(cmd);
352 }
353
354 /* Command NICK. Shows current nickname/sets new nickname on current
355    window. */
356
357 SILC_CLIENT_CMD_FUNC(nick)
358 {
359   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
360   SilcClientConnection conn = cmd->conn;
361   SilcBuffer buffer;
362
363   if (!cmd->conn) {
364     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
365     COMMAND_ERROR;
366     goto out;
367   }
368
369   if (!strcmp(conn->nickname, cmd->argv[1]))
370     goto out;
371
372   /* Show current nickname */
373   if (cmd->argc < 2) {
374     if (cmd->conn) {
375       cmd->client->ops->say(cmd->client, conn, 
376                             "Your nickname is %s on server %s", 
377                             conn->nickname, conn->remote_host);
378     } else {
379       cmd->client->ops->say(cmd->client, conn, 
380                             "Your nickname is %s", conn->nickname);
381     }
382
383     /* XXX Notify application */
384     COMMAND;
385     goto out;
386   }
387
388   /* Set new nickname */
389   buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
390                                        cmd->argc - 1, ++cmd->argv,
391                                        ++cmd->argv_lens, ++cmd->argv_types,
392                                        ++cmd->conn->cmd_ident);
393   silc_client_packet_send(cmd->client, cmd->conn->sock,
394                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
395                           buffer->data, buffer->len, TRUE);
396   silc_buffer_free(buffer);
397   cmd->argv--;
398   cmd->argv_lens--;
399   cmd->argv_types--;
400   if (conn->nickname)
401     silc_free(conn->nickname);
402   conn->nickname = strdup(cmd->argv[1]);
403
404   /* Notify application */
405   COMMAND;
406
407  out:
408   silc_client_command_free(cmd);
409 }
410
411 /* Command LIST. Lists channels on the current server. */
412
413 SILC_CLIENT_CMD_FUNC(list)
414 {
415   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
416   SilcClientConnection conn = cmd->conn;
417   SilcIDCacheEntry id_cache = NULL;
418   SilcChannelEntry channel;
419   SilcBuffer buffer, idp = NULL;
420   char *name;
421
422   if (!cmd->conn) {
423     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
424     COMMAND_ERROR;
425     goto out;
426   }
427
428   if (cmd->argc == 2) {
429     name = cmd->argv[1];
430
431     /* Get the Channel ID of the channel */
432     if (silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
433       channel = (SilcChannelEntry)id_cache->context;
434       idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
435     }
436   }
437
438   if (!idp)
439     buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
440                                             ++conn->cmd_ident, 0);
441   else
442     buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
443                                             ++conn->cmd_ident, 1,
444                                             1, idp->data, idp->len);
445
446   silc_client_packet_send(cmd->client, cmd->conn->sock,
447                           SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
448                           buffer->data, buffer->len, TRUE);
449   silc_buffer_free(buffer);
450   if (idp)
451     silc_buffer_free(idp);
452
453   /* Notify application */
454   COMMAND;
455
456  out:
457   silc_client_command_free(cmd);
458 }
459
460 /* Command TOPIC. Sets/shows topic on a channel. */
461
462 SILC_CLIENT_CMD_FUNC(topic)
463 {
464   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
465   SilcClientConnection conn = cmd->conn;
466   SilcIDCacheEntry id_cache = NULL;
467   SilcChannelEntry channel;
468   SilcBuffer buffer, idp;
469   char *name;
470
471   if (!cmd->conn) {
472     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
473     COMMAND_ERROR;
474     goto out;
475   }
476
477   if (cmd->argc < 2 || cmd->argc > 3) {
478     cmd->client->ops->say(cmd->client, conn,
479                           "Usage: /TOPIC <channel> [<topic>]");
480     COMMAND_ERROR;
481     goto out;
482   }
483
484   if (cmd->argv[1][0] == '*') {
485     if (!conn->current_channel) {
486       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
487       COMMAND_ERROR;
488       goto out;
489     }
490     name = conn->current_channel->channel_name;
491   } else {
492     name = cmd->argv[1];
493   }
494
495   if (!conn->current_channel) {
496     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
497     COMMAND_ERROR;
498     goto out;
499   }
500
501   /* Get the Channel ID of the channel */
502   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
503     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
504     COMMAND_ERROR;
505     goto out;
506   }
507
508   channel = (SilcChannelEntry)id_cache->context;
509
510   /* Send TOPIC command to the server */
511   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
512   if (cmd->argc > 2)
513     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2, 
514                                             1, idp->data, idp->len,
515                                             2, cmd->argv[2], 
516                                             strlen(cmd->argv[2]));
517   else
518     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1, 
519                                             1, idp->data, idp->len,
520                                             0);
521   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
522                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
523   silc_buffer_free(buffer);
524   silc_buffer_free(idp);
525
526   /* Notify application */
527   COMMAND;
528
529  out:
530   silc_client_command_free(cmd);
531 }
532
533 /* Command INVITE. Invites specific client to join a channel. This is
534    also used to mange the invite list of the channel. */
535
536 SILC_CLIENT_CMD_FUNC(invite)
537 {
538   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
539   SilcClient client = cmd->client;
540   SilcClientConnection conn = cmd->conn;
541   SilcClientEntry client_entry = NULL;
542   SilcChannelEntry channel;
543   SilcBuffer buffer, clidp, chidp;
544   unsigned int num = 0, type = 0;
545   char *nickname = NULL, *server = NULL, *name;
546   char *invite = NULL;
547
548   if (!cmd->conn) {
549     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
550     COMMAND_ERROR;
551     goto out;
552   }
553
554   if (cmd->argc < 2) {
555     cmd->client->ops->say(cmd->client, conn,
556                    "Usage: /INVITE <channel> [<nickname>[@server>]"
557                    "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
558     COMMAND_ERROR;
559     goto out;
560   }
561
562   if (cmd->argv[1][0] == '*') {
563     if (!conn->current_channel) {
564       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
565       COMMAND_ERROR;
566       goto out;
567     }
568
569     channel = conn->current_channel;
570   } else {
571     name = cmd->argv[1];
572
573     channel = silc_client_get_channel(cmd->client, conn, name);
574     if (!channel) {
575       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
576       COMMAND_ERROR;
577       goto out;
578     }
579   }
580
581   /* Parse the typed nickname. */
582   if (cmd->argc == 3) {
583     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
584       if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
585         cmd->client->ops->say(cmd->client, conn, "Bad nickname");
586         COMMAND_ERROR;
587         goto out;
588       }
589       
590       /* Find client entry */
591       client_entry = silc_idlist_get_client(client, conn, nickname, 
592                                             server, num, TRUE);
593       if (!client_entry) {
594         if (nickname)
595           silc_free(nickname);
596         if (server)
597           silc_free(server);
598         
599         if (cmd->pending) {
600           COMMAND_ERROR;
601           goto out;
602         }
603       
604         /* Client entry not found, it was requested thus mark this to be
605            pending command. */
606         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
607                                     conn->cmd_ident,
608                                     silc_client_command_destructor,
609                                     silc_client_command_invite, 
610                                     silc_client_command_dup(cmd));
611         cmd->pending = 1;
612         return;
613       }
614       
615       cmd->client->ops->say(cmd->client, conn, 
616                             "Inviting %s to channel %s", cmd->argv[2], 
617                             channel->channel_name);
618     } else {
619       invite = cmd->argv[2];
620       invite++;
621       if (cmd->argv[2][0] == '+')
622         type = 3;
623       else
624         type = 4;
625     }
626   }
627
628   /* Send the command */
629   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
630   if (client_entry) {
631     clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
632     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
633                                             ++conn->cmd_ident, 3,
634                                             1, chidp->data, chidp->len,
635                                             2, clidp->data, clidp->len,
636                                             type, invite, invite ?
637                                             strlen(invite) : 0);
638     silc_buffer_free(clidp);
639   } else {
640     buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
641                                             ++conn->cmd_ident, 2,
642                                             1, chidp->data, chidp->len,
643                                             type, invite, invite ?
644                                             strlen(invite) : 0);
645   }
646
647   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
648                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
649   silc_buffer_free(buffer);
650   silc_buffer_free(chidp);
651
652   /* Notify application */
653   COMMAND;
654
655  out:
656   if (nickname)
657     silc_free(nickname);
658   if (server)
659     silc_free(server);
660   silc_client_command_free(cmd);
661 }
662
663 typedef struct {
664   SilcClient client;
665   SilcClientConnection conn;
666 } *QuitInternal;
667
668 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
669 {
670   QuitInternal q = (QuitInternal)context;
671
672   /* Close connection */
673   q->client->ops->disconnect(q->client, q->conn);
674   silc_client_close_connection(q->client, q->conn->sock->user_data);
675
676   silc_free(q);
677 }
678
679 /* Command QUIT. Closes connection with current server. */
680  
681 SILC_CLIENT_CMD_FUNC(quit)
682 {
683   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
684   SilcBuffer buffer;
685   QuitInternal q;
686
687   if (!cmd->conn) {
688     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
689     COMMAND_ERROR;
690     goto out;
691   }
692
693   if (cmd->argc > 1)
694     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, 
695                                          &cmd->argv[1], &cmd->argv_lens[1],
696                                          &cmd->argv_types[1], 0);
697   else
698     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
699                                          NULL, NULL, NULL, 0);
700   silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, 
701                           NULL, 0, NULL, NULL, 
702                           buffer->data, buffer->len, TRUE);
703   silc_buffer_free(buffer);
704
705   q = silc_calloc(1, sizeof(*q));
706   q->client = cmd->client;
707   q->conn = cmd->conn;
708
709   /* We quit the connection with little timeout */
710   silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
711                      silc_client_command_quit_cb, (void *)q,
712                      1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
713
714   /* Notify application */
715   COMMAND;
716
717  out:
718   silc_client_command_free(cmd);
719 }
720
721 /* Command KILL. Router operator can use this command to remove an client
722    fromthe SILC Network. */
723
724 SILC_CLIENT_CMD_FUNC(kill)
725 {
726   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
727   SilcClientConnection conn = cmd->conn;
728   SilcBuffer buffer, idp;
729   SilcClientEntry target;
730   unsigned int num = 0;
731   char *nickname = NULL, *server = NULL;
732
733   if (!cmd->conn) {
734     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
735     COMMAND_ERROR;
736     goto out;
737   }
738
739   if (cmd->argc < 2) {
740     cmd->client->ops->say(cmd->client, conn, 
741                           "Usage: /KILL <nickname> [<comment>]");
742     COMMAND_ERROR;
743     goto out;
744   }
745
746   /* Parse the typed nickname. */
747   if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
748     cmd->client->ops->say(cmd->client, conn, "Bad nickname");
749     COMMAND_ERROR;
750     goto out;
751   }
752
753   /* Get the target client */
754   target = silc_idlist_get_client(cmd->client, conn, nickname, 
755                                   server, num, TRUE);
756   if (!target) {
757     silc_free(nickname);
758     if (server)
759       silc_free(server);
760
761     if (cmd->pending) {
762       COMMAND_ERROR;
763       goto out;
764     }
765
766     /* Client entry not found, it was requested thus mark this to be
767        pending command. */
768     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
769                                 conn->cmd_ident,  
770                                 silc_client_command_destructor,
771                                 silc_client_command_kill, 
772                                 silc_client_command_dup(cmd));
773     cmd->pending = 1;
774     return;
775   }
776
777   /* Send the KILL command to the server */
778   idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
779   if (cmd->argc == 2)
780     buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1, 
781                                             1, idp->data, idp->len);
782   else
783     buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2, 
784                                             1, idp->data, idp->len,
785                                             2, cmd->argv[2], 
786                                             strlen(cmd->argv[2]));
787   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
788                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
789   silc_buffer_free(buffer);
790   silc_buffer_free(idp);
791
792   /* Notify application */
793   COMMAND;
794
795  out:
796   if (nickname)
797     silc_free(nickname);
798   if (server)
799     silc_free(server);
800   silc_client_command_free(cmd);
801 }
802
803 /* Command INFO. Request information about specific server. If specific
804    server is not provided the current server is used. */
805
806 SILC_CLIENT_CMD_FUNC(info)
807 {
808   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
809   SilcClientConnection conn = cmd->conn;
810   SilcBuffer buffer;
811   char *name;
812
813   if (!cmd->conn) {
814     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
815     COMMAND_ERROR;
816     goto out;
817   }
818
819   if (cmd->argc < 2)
820     name = strdup(conn->remote_host);
821   else
822     name = strdup(cmd->argv[1]);
823
824   /* Send the command */
825   buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, 
826                                           1, name, strlen(name));
827   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
828                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
829   silc_buffer_free(buffer);
830
831   /* Notify application */
832   COMMAND;
833
834  out:
835   silc_client_command_free(cmd);
836 }
837
838 /* Command PING. Sends ping to server. This is used to test the 
839    communication channel. */
840
841 SILC_CLIENT_CMD_FUNC(ping)
842 {
843   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
844   SilcClientConnection conn = cmd->conn;
845   SilcBuffer buffer;
846   void *id;
847   int i;
848   char *name = NULL;
849
850   if (!cmd->conn) {
851     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
852     COMMAND_ERROR;
853     goto out;
854   }
855
856   if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
857     name = strdup(conn->remote_host);
858
859   /* Send the command */
860   buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
861                                           1, conn->remote_id_data, 
862                                           SILC_ID_SERVER_LEN);
863   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
864                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
865   silc_buffer_free(buffer);
866
867   id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
868                       SILC_ID_SERVER);
869   if (!id) {
870     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
871     COMMAND_ERROR;
872     goto out;
873   }
874
875   /* Start counting time */
876   for (i = 0; i < conn->ping_count; i++) {
877     if (conn->ping[i].dest_id == NULL) {
878       conn->ping[i].start_time = time(NULL);
879       conn->ping[i].dest_id = id;
880       conn->ping[i].dest_name = name;
881       conn->ping_count++;
882       break;
883     }
884   }
885   if (i >= conn->ping_count) {
886     i = conn->ping_count;
887     conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
888     conn->ping[i].start_time = time(NULL);
889     conn->ping[i].dest_id = id;
890     conn->ping[i].dest_name = name;
891     conn->ping_count++;
892   }
893   
894   /* Notify application */
895   COMMAND;
896
897  out:
898   silc_client_command_free(cmd);
899 }
900
901 SILC_CLIENT_CMD_FUNC(notice)
902 {
903 }
904
905 /* Command JOIN. Joins to a channel. */
906
907 SILC_CLIENT_CMD_FUNC(join)
908 {
909   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
910   SilcClientConnection conn = cmd->conn;
911   SilcIDCacheEntry id_cache = NULL;
912   SilcBuffer buffer, idp;
913
914   if (!cmd->conn) {
915     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
916     COMMAND_ERROR;
917     goto out;
918   }
919
920   if (cmd->argc < 2) {
921     /* Show channels currently joined to */
922
923     goto out;
924   }
925
926   /* See if we have joined to the requested channel already */
927   if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
928                                     &id_cache)) {
929     cmd->client->ops->say(cmd->client, conn, 
930                           "You are talking to channel %s", cmd->argv[1]);
931     conn->current_channel = (SilcChannelEntry)id_cache->context;
932 #if 0
933     cmd->client->screen->bottom_line->channel = cmd->argv[1];
934     silc_screen_print_bottom_line(cmd->client->screen, 0);
935 #endif
936     goto out;
937   }
938
939   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
940
941   /* Send JOIN command to the server */
942   if (cmd->argc == 2)
943     buffer = 
944       silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
945                                      1, cmd->argv[1], cmd->argv_lens[1],
946                                      2, idp->data, idp->len);
947   else if (cmd->argc == 3)
948     /* XXX Buggy */
949     buffer = 
950       silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
951                                      1, cmd->argv[1], cmd->argv_lens[1],
952                                      2, idp->data, idp->len,
953                                      3, cmd->argv[2], cmd->argv_lens[2]);
954   else
955     buffer = 
956       silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
957                                      1, cmd->argv[1], cmd->argv_lens[1],
958                                      2, idp->data, idp->len,
959                                      3, cmd->argv[2], cmd->argv_lens[2],
960                                      4, cmd->argv[3], cmd->argv_lens[3]);
961
962   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
963                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
964   silc_buffer_free(buffer);
965   silc_buffer_free(idp);
966
967   /* Notify application */
968   COMMAND;
969
970  out:
971   silc_client_command_free(cmd);
972 }
973
974 /* MOTD command. Requests motd from server. */
975
976 SILC_CLIENT_CMD_FUNC(motd)
977 {
978   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
979   SilcClientConnection conn = cmd->conn;
980   SilcBuffer buffer;
981
982   if (!cmd->conn) {
983     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
984     COMMAND_ERROR;
985     goto out;
986   }
987
988   if (cmd->argc < 1 || cmd->argc > 2) {
989     cmd->client->ops->say(cmd->client, conn,
990                           "Usage: /MOTD [<server>]");
991     COMMAND_ERROR;
992     goto out;
993   }
994
995   /* Send TOPIC command to the server */
996   if (cmd->argc == 1)
997     buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
998                                             1, conn->remote_host, 
999                                             strlen(conn->remote_host));
1000   else
1001     buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
1002                                             1, cmd->argv[1], 
1003                                             cmd->argv_lens[1]);
1004   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1005                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1006   silc_buffer_free(buffer);
1007
1008   /* Notify application */
1009   COMMAND;
1010
1011  out:
1012   silc_client_command_free(cmd);
1013 }
1014
1015 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
1016    modes as client cannot set itself server/router operator privileges. */
1017
1018 SILC_CLIENT_CMD_FUNC(umode)
1019 {
1020   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1021   SilcClientConnection conn = cmd->conn;
1022   SilcBuffer buffer, idp;
1023   unsigned char *cp, modebuf[4];
1024   unsigned int mode, add, len;
1025   int i;
1026
1027   if (!cmd->conn) {
1028     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1029     COMMAND_ERROR;
1030     goto out;
1031   }
1032
1033   if (cmd->argc < 2) {
1034     cmd->client->ops->say(cmd->client, conn, 
1035                   "Usage: /UMODE +|-<modes>");
1036     COMMAND_ERROR;
1037     goto out;
1038   }
1039
1040   mode = conn->local_entry->mode;
1041
1042   /* Are we adding or removing mode */
1043   if (cmd->argv[1][0] == '-')
1044     add = FALSE;
1045   else
1046     add = TRUE;
1047
1048   /* Parse mode */
1049   cp = cmd->argv[1] + 1;
1050   len = strlen(cp);
1051   for (i = 0; i < len; i++) {
1052     switch(cp[i]) {
1053     case 'a':
1054       if (add) {
1055         mode = 0;
1056         mode |= SILC_UMODE_SERVER_OPERATOR;
1057         mode |= SILC_UMODE_ROUTER_OPERATOR;
1058       } else {
1059         mode = SILC_UMODE_NONE;
1060       }
1061       break;
1062     case 's':
1063       if (add)
1064         mode |= SILC_UMODE_SERVER_OPERATOR;
1065       else
1066         mode &= ~SILC_UMODE_SERVER_OPERATOR;
1067       break;
1068     case 'r':
1069       if (add)
1070         mode |= SILC_UMODE_ROUTER_OPERATOR;
1071       else
1072         mode &= ~SILC_UMODE_ROUTER_OPERATOR;
1073       break;
1074     default:
1075       COMMAND_ERROR;
1076       goto out;
1077       break;
1078     }
1079   }
1080
1081   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
1082   SILC_PUT32_MSB(mode, modebuf);
1083
1084   /* Send the command packet. We support sending only one mode at once
1085      that requires an argument. */
1086   buffer = 
1087     silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, 
1088                                    1, idp->data, idp->len, 
1089                                    2, modebuf, sizeof(modebuf));
1090   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1091                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1092   silc_buffer_free(buffer);
1093   silc_buffer_free(idp);
1094
1095   /* Notify application */
1096   COMMAND;
1097
1098  out:
1099   silc_client_command_free(cmd);
1100 }
1101
1102 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1103    can be set several at once. Those modes that require argument must be set
1104    separately (unless set with modes that does not require arguments). */
1105
1106 SILC_CLIENT_CMD_FUNC(cmode)
1107 {
1108   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1109   SilcClientConnection conn = cmd->conn;
1110   SilcChannelEntry channel;
1111   SilcBuffer buffer, chidp;
1112   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1113   unsigned int mode, add, type, len, arg_len = 0;
1114   int i;
1115
1116   if (!cmd->conn) {
1117     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1118     COMMAND_ERROR;
1119     goto out;
1120   }
1121
1122   if (cmd->argc < 3) {
1123     cmd->client->ops->say(cmd->client, conn, 
1124                   "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1125     COMMAND_ERROR;
1126     goto out;
1127   }
1128
1129   if (cmd->argv[1][0] == '*') {
1130     if (!conn->current_channel) {
1131       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1132       COMMAND_ERROR;
1133       goto out;
1134     }
1135
1136     channel = conn->current_channel;
1137   } else {
1138     name = cmd->argv[1];
1139
1140     channel = silc_client_get_channel(cmd->client, conn, name);
1141     if (!channel) {
1142       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1143       COMMAND_ERROR;
1144       goto out;
1145     }
1146   }
1147
1148   mode = channel->mode;
1149
1150   /* Are we adding or removing mode */
1151   if (cmd->argv[2][0] == '-')
1152     add = FALSE;
1153   else
1154     add = TRUE;
1155
1156   /* Argument type to be sent to server */
1157   type = 0;
1158
1159   /* Parse mode */
1160   cp = cmd->argv[2] + 1;
1161   len = strlen(cp);
1162   for (i = 0; i < len; i++) {
1163     switch(cp[i]) {
1164     case 'p':
1165       if (add)
1166         mode |= SILC_CHANNEL_MODE_PRIVATE;
1167       else
1168         mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1169       break;
1170     case 's':
1171       if (add)
1172         mode |= SILC_CHANNEL_MODE_SECRET;
1173       else
1174         mode &= ~SILC_CHANNEL_MODE_SECRET;
1175       break;
1176     case 'k':
1177       if (add)
1178         mode |= SILC_CHANNEL_MODE_PRIVKEY;
1179       else
1180         mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1181       break;
1182     case 'i':
1183       if (add)
1184         mode |= SILC_CHANNEL_MODE_INVITE;
1185       else
1186         mode &= ~SILC_CHANNEL_MODE_INVITE;
1187       break;
1188     case 't':
1189       if (add)
1190         mode |= SILC_CHANNEL_MODE_TOPIC;
1191       else
1192         mode &= ~SILC_CHANNEL_MODE_TOPIC;
1193       break;
1194     case 'l':
1195       if (add) {
1196         int ll;
1197         mode |= SILC_CHANNEL_MODE_ULIMIT;
1198         type = 3;
1199         ll = atoi(cmd->argv[3]);
1200         SILC_PUT32_MSB(ll, tmp);
1201         arg = tmp;
1202         arg_len = 4;
1203       } else {
1204         mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1205       }
1206       break;
1207     case 'a':
1208       if (add) {
1209         mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1210         type = 4;
1211         arg = cmd->argv[3];
1212         arg_len = cmd->argv_lens[3];
1213       } else {
1214         mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1215       }
1216       break;
1217     case 'c':
1218       if (add) {
1219         mode |= SILC_CHANNEL_MODE_CIPHER;
1220         type = 5;
1221         arg = cmd->argv[3];
1222         arg_len = cmd->argv_lens[3];
1223       } else {
1224         mode &= ~SILC_CHANNEL_MODE_CIPHER;
1225       }
1226       break;
1227     case 'h':
1228       if (add) {
1229         mode |= SILC_CHANNEL_MODE_HMAC;
1230         type = 6;
1231         arg = cmd->argv[3];
1232         arg_len = cmd->argv_lens[3];
1233       } else {
1234         mode &= ~SILC_CHANNEL_MODE_HMAC;
1235       }
1236       break;
1237     default:
1238       COMMAND_ERROR;
1239       goto out;
1240       break;
1241     }
1242   }
1243
1244   if (type && cmd->argc < 3) {
1245     COMMAND_ERROR;
1246     goto out;
1247   }
1248
1249   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1250   SILC_PUT32_MSB(mode, modebuf);
1251
1252   /* Send the command packet. We support sending only one mode at once
1253      that requires an argument. */
1254   if (type && arg) {
1255     buffer = 
1256       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
1257                                      1, chidp->data, chidp->len, 
1258                                      2, modebuf, sizeof(modebuf),
1259                                      type, arg, arg_len);
1260   } else {
1261     buffer = 
1262       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
1263                                      1, chidp->data, chidp->len, 
1264                                      2, modebuf, sizeof(modebuf));
1265   }
1266
1267   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1268                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1269   silc_buffer_free(buffer);
1270   silc_buffer_free(chidp);
1271
1272   /* Notify application */
1273   COMMAND;
1274
1275  out:
1276   silc_client_command_free(cmd);
1277 }
1278
1279 /* CUMODE command. Changes client's mode on a channel. */
1280
1281 SILC_CLIENT_CMD_FUNC(cumode)
1282 {
1283   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1284   SilcClientConnection conn = cmd->conn;
1285   SilcChannelEntry channel;
1286   SilcChannelUser chu;
1287   SilcClientEntry client_entry;
1288   SilcBuffer buffer, clidp, chidp;
1289   unsigned char *name, *cp, modebuf[4];
1290   unsigned int mode = 0, add, len;
1291   char *nickname = NULL, *server = NULL;
1292   unsigned int num = 0;
1293   int i;
1294
1295   if (!cmd->conn) {
1296     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1297     COMMAND_ERROR;
1298     goto out;
1299   }
1300
1301   if (cmd->argc < 4) {
1302     cmd->client->ops->say(cmd->client, conn, 
1303                   "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1304     COMMAND_ERROR;
1305     goto out;
1306   }
1307
1308   if (cmd->argv[1][0] == '*') {
1309     if (!conn->current_channel) {
1310       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1311       COMMAND_ERROR;
1312       goto out;
1313     }
1314
1315     channel = conn->current_channel;
1316   } else {
1317     name = cmd->argv[1];
1318
1319     channel = silc_client_get_channel(cmd->client, conn, name);
1320     if (!channel) {
1321       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1322       COMMAND_ERROR;
1323       goto out;
1324     }
1325   }
1326
1327   /* Parse the typed nickname. */
1328   if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1329     cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1330     COMMAND_ERROR;
1331     goto out;
1332   }
1333
1334   /* Find client entry */
1335   client_entry = silc_idlist_get_client(cmd->client, conn, 
1336                                         nickname, server, num, TRUE);
1337   if (!client_entry) {
1338     if (cmd->pending) {
1339       COMMAND_ERROR;
1340       goto out;
1341     }
1342
1343     /* Client entry not found, it was requested thus mark this to be
1344        pending command. */
1345     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
1346                                 conn->cmd_ident,  
1347                                 silc_client_command_destructor,
1348                                 silc_client_command_cumode, 
1349                                 silc_client_command_dup(cmd));
1350     cmd->pending = 1;
1351     return;
1352   }
1353   
1354   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1355     if (chu->client == client_entry) {
1356       chu->mode = mode;
1357       break;
1358     }
1359   }
1360
1361   /* Are we adding or removing mode */
1362   if (cmd->argv[2][0] == '-')
1363     add = FALSE;
1364   else
1365     add = TRUE;
1366
1367   /* Parse mode */
1368   cp = cmd->argv[2] + 1;
1369   len = strlen(cp);
1370   for (i = 0; i < len; i++) {
1371     switch(cp[i]) {
1372     case 'a':
1373       if (add) {
1374         mode |= SILC_CHANNEL_UMODE_CHANFO;
1375         mode |= SILC_CHANNEL_UMODE_CHANOP;
1376       } else {
1377         mode = SILC_CHANNEL_UMODE_NONE;
1378       }
1379       break;
1380     case 'f':
1381       if (add)
1382         mode |= SILC_CHANNEL_UMODE_CHANFO;
1383       else
1384         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1385       break;
1386     case 'o':
1387       if (add)
1388         mode |= SILC_CHANNEL_UMODE_CHANOP;
1389       else
1390         mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1391       break;
1392     default:
1393       COMMAND_ERROR;
1394       goto out;
1395       break;
1396     }
1397   }
1398
1399   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1400   SILC_PUT32_MSB(mode, modebuf);
1401   clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1402
1403   /* Send the command packet. We support sending only one mode at once
1404      that requires an argument. */
1405   buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3, 
1406                                           1, chidp->data, chidp->len, 
1407                                           2, modebuf, 4,
1408                                           3, clidp->data, clidp->len);
1409
1410   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1411                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1412   silc_buffer_free(buffer);
1413   silc_buffer_free(chidp);
1414   silc_buffer_free(clidp);
1415   
1416   /* Notify application */
1417   COMMAND;
1418
1419  out:
1420   if (nickname)
1421     silc_free(nickname);
1422   if (server)
1423     silc_free(server);
1424   silc_client_command_free(cmd);
1425 }
1426
1427 /* KICK command. Kicks a client out of channel. */
1428
1429 SILC_CLIENT_CMD_FUNC(kick)
1430 {
1431   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1432   SilcClientConnection conn = cmd->conn;
1433   SilcIDCacheEntry id_cache = NULL;
1434   SilcChannelEntry channel;
1435   SilcBuffer buffer, idp, idp2;
1436   SilcClientEntry target;
1437   char *name;
1438   unsigned int num = 0;
1439   char *nickname = NULL, *server = NULL;
1440
1441   if (!cmd->conn) {
1442     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1443     COMMAND_ERROR;
1444     goto out;
1445   }
1446
1447   if (cmd->argc < 3) {
1448     cmd->client->ops->say(cmd->client, conn, 
1449                           "Usage: /KICK <channel> <nickname> [<comment>]");
1450     COMMAND_ERROR;
1451     goto out;
1452   }
1453
1454   if (cmd->argv[1][0] == '*') {
1455     if (!conn->current_channel) {
1456       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1457       COMMAND_ERROR;
1458       goto out;
1459     }
1460     name = conn->current_channel->channel_name;
1461   } else {
1462     name = cmd->argv[1];
1463   }
1464
1465   if (!conn->current_channel) {
1466     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1467     COMMAND_ERROR;
1468     goto out;
1469   }
1470
1471   /* Get the Channel ID of the channel */
1472   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1473     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1474     COMMAND_ERROR;
1475     goto out;
1476   }
1477
1478   channel = (SilcChannelEntry)id_cache->context;
1479
1480   /* Parse the typed nickname. */
1481   if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1482     cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1483     COMMAND_ERROR;
1484     goto out;
1485   }
1486
1487   /* Get the target client */
1488   target = silc_idlist_get_client(cmd->client, conn, nickname, 
1489                                   server, num, FALSE);
1490   if (!target) {
1491     cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1492                           cmd->argv[2]);
1493     COMMAND_ERROR;
1494     goto out;
1495   }
1496
1497   /* Send KICK command to the server */
1498   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1499   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1500   if (cmd->argc == 3)
1501     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
1502                                             1, idp->data, idp->len,
1503                                             2, idp2->data, idp2->len);
1504   else
1505     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
1506                                             1, idp->data, idp->len,
1507                                             2, idp2->data, idp2->len,
1508                                             3, cmd->argv[3], 
1509                                             strlen(cmd->argv[3]));
1510   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1511                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1512   silc_buffer_free(buffer);
1513   silc_buffer_free(idp);
1514   silc_buffer_free(idp2);
1515
1516   /* Notify application */
1517   COMMAND;
1518
1519  out:
1520   if (nickname)
1521     silc_free(nickname);
1522   if (server)
1523     silc_free(server);
1524   silc_client_command_free(cmd);
1525 }
1526
1527 /* OPER command. Used to obtain server operator privileges. */
1528
1529 SILC_CLIENT_CMD_FUNC(oper)
1530 {
1531   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1532   SilcClientConnection conn = cmd->conn;
1533   SilcBuffer buffer;
1534   unsigned char *auth_data;
1535   SilcBuffer auth;
1536
1537   if (!cmd->conn) {
1538     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1539     COMMAND_ERROR;
1540     goto out;
1541   }
1542
1543   if (cmd->argc < 2) {
1544     cmd->client->ops->say(cmd->client, conn, 
1545                           "Usage: /OPER <username> [<public key>]");
1546     COMMAND_ERROR;
1547     goto out;
1548   }
1549
1550   if (cmd->argc == 3) {
1551     /* XXX Get public key */
1552     auth_data = NULL;
1553     COMMAND_ERROR;
1554     goto out;
1555   } else {
1556     /* Get passphrase */
1557
1558     auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1559     if (!auth_data) {
1560       COMMAND_ERROR;
1561       goto out;
1562     }
1563
1564     /* Encode the authentication payload */
1565     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1566                                     auth_data, strlen(auth_data));
1567   }
1568
1569   buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
1570                                           1, cmd->argv[1], 
1571                                           strlen(cmd->argv[1]),
1572                                           2, auth->data, auth->len);
1573   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1574                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1575
1576   silc_buffer_free(buffer);
1577   silc_buffer_free(auth);
1578   memset(auth_data, 0, strlen(auth_data));
1579   silc_free(auth_data);
1580
1581   /* Notify application */
1582   COMMAND;
1583
1584  out:
1585   silc_client_command_free(cmd);
1586 }
1587
1588 /* SILCOPER command. Used to obtain router operator privileges. */
1589
1590 SILC_CLIENT_CMD_FUNC(silcoper)
1591 {
1592   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1593   SilcClientConnection conn = cmd->conn;
1594   SilcBuffer buffer;
1595   unsigned char *auth_data;
1596   SilcBuffer auth;
1597
1598   if (!cmd->conn) {
1599     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1600     COMMAND_ERROR;
1601     goto out;
1602   }
1603
1604   if (cmd->argc < 2) {
1605     cmd->client->ops->say(cmd->client, conn, 
1606                           "Usage: /SILCOPER <username> [<public key>]");
1607     COMMAND_ERROR;
1608     goto out;
1609   }
1610
1611   if (cmd->argc == 3) {
1612     /* XXX Get public key */
1613     auth_data = NULL;
1614     COMMAND_ERROR;
1615     goto out;
1616   } else {
1617     /* Get passphrase */
1618
1619     auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1620     if (!auth_data) {
1621       COMMAND_ERROR;
1622       goto out;
1623     }
1624
1625     /* Encode the authentication payload */
1626     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1627                                     auth_data, strlen(auth_data));
1628   }
1629
1630   buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
1631                                           1, cmd->argv[1], 
1632                                           strlen(cmd->argv[1]),
1633                                           2, auth->data, auth->len);
1634   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1635                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1636
1637   silc_buffer_free(buffer);
1638   silc_buffer_free(auth);
1639   memset(auth_data, 0, strlen(auth_data));
1640   silc_free(auth_data);
1641
1642   /* Notify application */
1643   COMMAND;
1644
1645  out:
1646   silc_client_command_free(cmd);
1647 }
1648
1649 /* CONNECT command. Connects the server to another server. */
1650
1651 SILC_CLIENT_CMD_FUNC(connect)
1652 {
1653   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1654   SilcClientConnection conn = cmd->conn;
1655   SilcBuffer buffer;
1656   unsigned char port[4];
1657   unsigned int tmp;
1658
1659   if (!cmd->conn) {
1660     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1661     COMMAND_ERROR;
1662     goto out;
1663   }
1664
1665   if (cmd->argc < 2) {
1666     cmd->client->ops->say(cmd->client, conn, 
1667                           "Usage: /CONNECT <server> [<port>]");
1668     COMMAND_ERROR;
1669     goto out;
1670   }
1671
1672   if (cmd->argc == 3) {
1673     tmp = atoi(cmd->argv[2]);
1674     SILC_PUT32_MSB(tmp, port);
1675   }
1676
1677   if (cmd->argc == 3)
1678     buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2, 
1679                                             1, cmd->argv[1], 
1680                                             strlen(cmd->argv[1]),
1681                                             2, port, 4);
1682   else
1683     buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1684                                             1, cmd->argv[1], 
1685                                             strlen(cmd->argv[1]));
1686   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1687                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1688   silc_buffer_free(buffer);
1689
1690   /* Notify application */
1691   COMMAND;
1692
1693  out:
1694   silc_client_command_free(cmd);
1695 }
1696
1697 SILC_CLIENT_CMD_FUNC(restart)
1698 {
1699 }
1700
1701 /* CLOSE command. Close server connection to the remote server */
1702  
1703 SILC_CLIENT_CMD_FUNC(close)
1704 {
1705   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1706   SilcClientConnection conn = cmd->conn;
1707   SilcBuffer buffer;
1708   unsigned char port[4];
1709   unsigned int tmp;
1710
1711   if (!cmd->conn) {
1712     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1713     COMMAND_ERROR;
1714     goto out;
1715   }
1716
1717   if (cmd->argc < 2) {
1718     cmd->client->ops->say(cmd->client, conn, 
1719                           "Usage: /CLOSE <server> [<port>]");
1720     COMMAND_ERROR;
1721     goto out;
1722   }
1723
1724   if (cmd->argc == 3) {
1725     tmp = atoi(cmd->argv[2]);
1726     SILC_PUT32_MSB(tmp, port);
1727   }
1728
1729   if (cmd->argc == 3)
1730     buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2, 
1731                                             1, cmd->argv[1], 
1732                                             strlen(cmd->argv[1]),
1733                                             2, port, 4);
1734   else
1735     buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1736                                             1, cmd->argv[1], 
1737                                             strlen(cmd->argv[1]));
1738   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1739                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1740   silc_buffer_free(buffer);
1741
1742   /* Notify application */
1743   COMMAND;
1744
1745  out:
1746   silc_client_command_free(cmd);
1747 }
1748  
1749 /* SHUTDOWN command. Shutdowns the server. */
1750
1751 SILC_CLIENT_CMD_FUNC(shutdown)
1752 {
1753   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1754
1755   if (!cmd->conn) {
1756     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1757     COMMAND_ERROR;
1758     goto out;
1759   }
1760
1761   /* Send the command */
1762   silc_client_send_command(cmd->client, cmd->conn, 
1763                            SILC_COMMAND_SHUTDOWN, 0, 0);
1764
1765   /* Notify application */
1766   COMMAND;
1767
1768  out:
1769   silc_client_command_free(cmd);
1770 }
1771  
1772 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1773
1774 SILC_CLIENT_CMD_FUNC(leave)
1775 {
1776   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1777   SilcClientConnection conn = cmd->conn;
1778   SilcIDCacheEntry id_cache = NULL;
1779   SilcChannelEntry channel;
1780   SilcBuffer buffer, idp;
1781   char *name;
1782
1783   if (!cmd->conn) {
1784     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1785     COMMAND_ERROR;
1786     goto out;
1787   }
1788
1789   if (cmd->argc != 2) {
1790     cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1791     COMMAND_ERROR;
1792     goto out;
1793   }
1794
1795   if (cmd->argv[1][0] == '*') {
1796     if (!conn->current_channel) {
1797       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1798       COMMAND_ERROR;
1799       goto out;
1800     }
1801     name = conn->current_channel->channel_name;
1802   } else {
1803     name = cmd->argv[1];
1804   }
1805
1806   if (!conn->current_channel) {
1807     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1808     COMMAND_ERROR;
1809     goto out;
1810   }
1811
1812   /* Get the Channel ID of the channel */
1813   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1814     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1815     COMMAND_ERROR;
1816     goto out;
1817   }
1818
1819   channel = (SilcChannelEntry)id_cache->context;
1820
1821   /* Send LEAVE command to the server */
1822   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1823   buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
1824                                           1, idp->data, idp->len);
1825   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1826                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1827   silc_buffer_free(buffer);
1828   silc_buffer_free(idp);
1829
1830   /* We won't talk anymore on this channel */
1831   cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1832
1833   conn->current_channel = NULL;
1834
1835   silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1836   silc_free(channel->channel_name);
1837   silc_free(channel->id);
1838   silc_free(channel->key);
1839   silc_cipher_free(channel->channel_key);
1840   silc_free(channel);
1841
1842   /* Notify application */
1843   COMMAND;
1844
1845  out:
1846   silc_client_command_free(cmd);
1847 }
1848
1849 /* Command USERS. Requests the USERS of the clients joined on requested
1850    channel. */
1851
1852 SILC_CLIENT_CMD_FUNC(users)
1853 {
1854   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1855   SilcClientConnection conn = cmd->conn;
1856   SilcIDCacheEntry id_cache = NULL;
1857   SilcChannelEntry channel;
1858   SilcBuffer buffer, idp;
1859   char *name, *line = NULL;
1860   unsigned int line_len = 0;
1861
1862   if (!cmd->conn) {
1863     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1864     COMMAND_ERROR;
1865     goto out;
1866   }
1867
1868   if (cmd->argc != 2) {
1869     cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1870     COMMAND_ERROR;
1871     goto out;
1872   }
1873
1874   if (cmd->argv[1][0] == '*') {
1875     if (!conn->current_channel) {
1876       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1877       COMMAND_ERROR;
1878       goto out;
1879     }
1880     name = conn->current_channel->channel_name;
1881   } else {
1882     name = cmd->argv[1];
1883   }
1884
1885   if (!conn->current_channel) {
1886     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1887     COMMAND_ERROR;
1888     goto out;
1889   }
1890
1891   /* Get the Channel ID of the channel */
1892   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1893     /* XXX should resolve the channel ID; LIST command */
1894     cmd->client->ops->say(cmd->client, conn, 
1895                           "You are not on that channel", name);
1896     COMMAND_ERROR;
1897     goto out;
1898   }
1899
1900   channel = (SilcChannelEntry)id_cache->context;
1901
1902   if (!cmd->pending) {
1903     /* Send USERS command to the server */
1904     idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1905     buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 
1906                                             ++conn->cmd_ident, 1, 
1907                                             1, idp->data, idp->len);
1908     silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
1909                             NULL, 0, NULL, NULL, buffer->data, 
1910                             buffer->len, TRUE);
1911     silc_buffer_free(buffer);
1912     silc_buffer_free(idp);
1913
1914     /* Register pending callback which will recall this command callback with
1915        same context and reprocesses the command. When reprocessing we actually
1916        display the information on the screen. */
1917     silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident, 
1918                                 silc_client_command_destructor,
1919                                 silc_client_command_users, 
1920                                 silc_client_command_dup(cmd));
1921     cmd->pending = TRUE;
1922     return;
1923   }
1924
1925   if (cmd->pending) {
1926     /* Pending command. Now we've resolved the information from server and
1927        we are ready to display the information on screen. */
1928     int i;
1929     SilcChannelUser chu;
1930
1931     cmd->client->ops->say(cmd->client, conn, "Users on %s", 
1932                           channel->channel_name);
1933
1934     line = silc_calloc(4096, sizeof(*line));
1935     line_len = 4096;
1936     silc_list_start(channel->clients);
1937     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1938       SilcClientEntry e = chu->client;
1939       char *m, tmp[80], len1;
1940
1941       memset(line, 0, sizeof(line_len));
1942
1943       if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1944         silc_free(line);
1945         line_len += strlen(e->nickname) + strlen(e->server) + 100;
1946         line = silc_calloc(line_len, sizeof(*line));
1947       }
1948
1949       memset(tmp, 0, sizeof(tmp));
1950       m = silc_client_chumode_char(chu->mode);
1951
1952       strncat(line, " ", 1);
1953       strncat(line, e->nickname, strlen(e->nickname));
1954       strncat(line, e->server ? "@" : "", 1);
1955
1956       len1 = 0;
1957       if (e->server)
1958         len1 = strlen(e->server);
1959       strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1960
1961       len1 = strlen(line);
1962       if (len1 >= 30) {
1963         memset(&line[29], 0, len1 - 29);
1964       } else {
1965         for (i = 0; i < 30 - len1 - 1; i++)
1966           strcat(line, " ");
1967       }
1968
1969       strncat(line, "  H", 3);
1970       strcat(tmp, m ? m : "");
1971       strncat(line, tmp, strlen(tmp));
1972
1973       if (strlen(tmp) < 5)
1974         for (i = 0; i < 5 - strlen(tmp); i++)
1975           strcat(line, " ");
1976
1977       strcat(line, e->username ? e->username : "");
1978
1979       cmd->client->ops->say(cmd->client, conn, "%s", line);
1980
1981       if (m)
1982         silc_free(m);
1983     }
1984   }
1985
1986   if (line)
1987     silc_free(line);
1988
1989   /* Notify application */
1990   COMMAND;
1991
1992  out:
1993   silc_client_command_free(cmd);
1994 }
1995
1996 /* Command BAN. This is used to manage the ban list of the channel. */
1997
1998 SILC_CLIENT_CMD_FUNC(ban)
1999 {
2000   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
2001   SilcClientConnection conn = cmd->conn;
2002   SilcChannelEntry channel;
2003   SilcBuffer buffer, chidp;
2004   int type = 0;
2005   char *name, *ban = NULL;
2006
2007   if (!cmd->conn) {
2008     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
2009     COMMAND_ERROR;
2010     goto out;
2011   }
2012
2013   if (cmd->argc < 2) {
2014     cmd->client->ops->say(cmd->client, conn, 
2015                    "Usage: /BAN <channel> "
2016                    "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2017     COMMAND_ERROR;
2018     goto out;
2019   }
2020
2021   if (cmd->argv[1][0] == '*') {
2022     if (!conn->current_channel) {
2023       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2024       COMMAND_ERROR;
2025       goto out;
2026     }
2027
2028     channel = conn->current_channel;
2029   } else {
2030     name = cmd->argv[1];
2031
2032     channel = silc_client_get_channel(cmd->client, conn, name);
2033     if (!channel) {
2034       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2035       COMMAND_ERROR;
2036       goto out;
2037     }
2038   }
2039
2040   if (cmd->argc == 3) {
2041     if (cmd->argv[2][0] == '+')
2042       type = 2;
2043     else
2044       type = 3;
2045
2046     ban = cmd->argv[2];
2047     ban++;
2048   }
2049
2050   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2051
2052   /* Send the command */
2053   if (ban)
2054     buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2, 
2055                                             1, chidp->data, chidp->len,
2056                                             type, ban, strlen(ban));
2057   else
2058     buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1, 
2059                                             1, chidp->data, chidp->len);
2060
2061   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
2062                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2063   silc_buffer_free(buffer);
2064   silc_buffer_free(chidp);
2065
2066   /* Notify application */
2067   COMMAND;
2068
2069  out:
2070   silc_client_command_free(cmd);
2071 }