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 = 8;
1221         arg = cmd->argv[3];
1222         arg_len = cmd->argv_lens[3];
1223       } else {
1224         mode &= ~SILC_CHANNEL_MODE_CIPHER;
1225       }
1226       break;
1227     default:
1228       COMMAND_ERROR;
1229       goto out;
1230       break;
1231     }
1232   }
1233
1234   if (type && cmd->argc < 3) {
1235     COMMAND_ERROR;
1236     goto out;
1237   }
1238
1239   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1240   SILC_PUT32_MSB(mode, modebuf);
1241
1242   /* Send the command packet. We support sending only one mode at once
1243      that requires an argument. */
1244   if (type && arg) {
1245     buffer = 
1246       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
1247                                      1, chidp->data, chidp->len, 
1248                                      2, modebuf, sizeof(modebuf),
1249                                      type, arg, arg_len);
1250   } else {
1251     buffer = 
1252       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
1253                                      1, chidp->data, chidp->len, 
1254                                      2, modebuf, sizeof(modebuf));
1255   }
1256
1257   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1258                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1259   silc_buffer_free(buffer);
1260   silc_buffer_free(chidp);
1261
1262   /* Notify application */
1263   COMMAND;
1264
1265  out:
1266   silc_client_command_free(cmd);
1267 }
1268
1269 /* CUMODE command. Changes client's mode on a channel. */
1270
1271 SILC_CLIENT_CMD_FUNC(cumode)
1272 {
1273   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1274   SilcClientConnection conn = cmd->conn;
1275   SilcChannelEntry channel;
1276   SilcChannelUser chu;
1277   SilcClientEntry client_entry;
1278   SilcBuffer buffer, clidp, chidp;
1279   unsigned char *name, *cp, modebuf[4];
1280   unsigned int mode = 0, add, len;
1281   char *nickname = NULL, *server = NULL;
1282   unsigned int num = 0;
1283   int i;
1284
1285   if (!cmd->conn) {
1286     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1287     COMMAND_ERROR;
1288     goto out;
1289   }
1290
1291   if (cmd->argc < 4) {
1292     cmd->client->ops->say(cmd->client, conn, 
1293                   "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1294     COMMAND_ERROR;
1295     goto out;
1296   }
1297
1298   if (cmd->argv[1][0] == '*') {
1299     if (!conn->current_channel) {
1300       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1301       COMMAND_ERROR;
1302       goto out;
1303     }
1304
1305     channel = conn->current_channel;
1306   } else {
1307     name = cmd->argv[1];
1308
1309     channel = silc_client_get_channel(cmd->client, conn, name);
1310     if (!channel) {
1311       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1312       COMMAND_ERROR;
1313       goto out;
1314     }
1315   }
1316
1317   /* Parse the typed nickname. */
1318   if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1319     cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1320     COMMAND_ERROR;
1321     goto out;
1322   }
1323
1324   /* Find client entry */
1325   client_entry = silc_idlist_get_client(cmd->client, conn, 
1326                                         nickname, server, num, TRUE);
1327   if (!client_entry) {
1328     if (cmd->pending) {
1329       COMMAND_ERROR;
1330       goto out;
1331     }
1332
1333     /* Client entry not found, it was requested thus mark this to be
1334        pending command. */
1335     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
1336                                 conn->cmd_ident,  
1337                                 silc_client_command_destructor,
1338                                 silc_client_command_cumode, 
1339                                 silc_client_command_dup(cmd));
1340     cmd->pending = 1;
1341     return;
1342   }
1343   
1344   while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1345     if (chu->client == client_entry) {
1346       chu->mode = mode;
1347       break;
1348     }
1349   }
1350
1351   /* Are we adding or removing mode */
1352   if (cmd->argv[2][0] == '-')
1353     add = FALSE;
1354   else
1355     add = TRUE;
1356
1357   /* Parse mode */
1358   cp = cmd->argv[2] + 1;
1359   len = strlen(cp);
1360   for (i = 0; i < len; i++) {
1361     switch(cp[i]) {
1362     case 'a':
1363       if (add) {
1364         mode |= SILC_CHANNEL_UMODE_CHANFO;
1365         mode |= SILC_CHANNEL_UMODE_CHANOP;
1366       } else {
1367         mode = SILC_CHANNEL_UMODE_NONE;
1368       }
1369       break;
1370     case 'f':
1371       if (add)
1372         mode |= SILC_CHANNEL_UMODE_CHANFO;
1373       else
1374         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1375       break;
1376     case 'o':
1377       if (add)
1378         mode |= SILC_CHANNEL_UMODE_CHANOP;
1379       else
1380         mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1381       break;
1382     default:
1383       COMMAND_ERROR;
1384       goto out;
1385       break;
1386     }
1387   }
1388
1389   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1390   SILC_PUT32_MSB(mode, modebuf);
1391   clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1392
1393   /* Send the command packet. We support sending only one mode at once
1394      that requires an argument. */
1395   buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3, 
1396                                           1, chidp->data, chidp->len, 
1397                                           2, modebuf, 4,
1398                                           3, clidp->data, clidp->len);
1399
1400   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1401                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1402   silc_buffer_free(buffer);
1403   silc_buffer_free(chidp);
1404   silc_buffer_free(clidp);
1405   
1406   /* Notify application */
1407   COMMAND;
1408
1409  out:
1410   if (nickname)
1411     silc_free(nickname);
1412   if (server)
1413     silc_free(server);
1414   silc_client_command_free(cmd);
1415 }
1416
1417 /* KICK command. Kicks a client out of channel. */
1418
1419 SILC_CLIENT_CMD_FUNC(kick)
1420 {
1421   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1422   SilcClientConnection conn = cmd->conn;
1423   SilcIDCacheEntry id_cache = NULL;
1424   SilcChannelEntry channel;
1425   SilcBuffer buffer, idp, idp2;
1426   SilcClientEntry target;
1427   char *name;
1428   unsigned int num = 0;
1429   char *nickname = NULL, *server = NULL;
1430
1431   if (!cmd->conn) {
1432     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1433     COMMAND_ERROR;
1434     goto out;
1435   }
1436
1437   if (cmd->argc < 3) {
1438     cmd->client->ops->say(cmd->client, conn, 
1439                           "Usage: /KICK <channel> <nickname> [<comment>]");
1440     COMMAND_ERROR;
1441     goto out;
1442   }
1443
1444   if (cmd->argv[1][0] == '*') {
1445     if (!conn->current_channel) {
1446       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1447       COMMAND_ERROR;
1448       goto out;
1449     }
1450     name = conn->current_channel->channel_name;
1451   } else {
1452     name = cmd->argv[1];
1453   }
1454
1455   if (!conn->current_channel) {
1456     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1457     COMMAND_ERROR;
1458     goto out;
1459   }
1460
1461   /* Get the Channel ID of the channel */
1462   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1463     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1464     COMMAND_ERROR;
1465     goto out;
1466   }
1467
1468   channel = (SilcChannelEntry)id_cache->context;
1469
1470   /* Parse the typed nickname. */
1471   if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1472     cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1473     COMMAND_ERROR;
1474     goto out;
1475   }
1476
1477   /* Get the target client */
1478   target = silc_idlist_get_client(cmd->client, conn, nickname, 
1479                                   server, num, FALSE);
1480   if (!target) {
1481     cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1482                           cmd->argv[2]);
1483     COMMAND_ERROR;
1484     goto out;
1485   }
1486
1487   /* Send KICK command to the server */
1488   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1489   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1490   if (cmd->argc == 3)
1491     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
1492                                             1, idp->data, idp->len,
1493                                             2, idp2->data, idp2->len);
1494   else
1495     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
1496                                             1, idp->data, idp->len,
1497                                             2, idp2->data, idp2->len,
1498                                             3, cmd->argv[3], 
1499                                             strlen(cmd->argv[3]));
1500   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1501                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1502   silc_buffer_free(buffer);
1503   silc_buffer_free(idp);
1504   silc_buffer_free(idp2);
1505
1506   /* Notify application */
1507   COMMAND;
1508
1509  out:
1510   if (nickname)
1511     silc_free(nickname);
1512   if (server)
1513     silc_free(server);
1514   silc_client_command_free(cmd);
1515 }
1516
1517 /* OPER command. Used to obtain server operator privileges. */
1518
1519 SILC_CLIENT_CMD_FUNC(oper)
1520 {
1521   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1522   SilcClientConnection conn = cmd->conn;
1523   SilcBuffer buffer;
1524   unsigned char *auth_data;
1525   SilcBuffer auth;
1526
1527   if (!cmd->conn) {
1528     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1529     COMMAND_ERROR;
1530     goto out;
1531   }
1532
1533   if (cmd->argc < 2) {
1534     cmd->client->ops->say(cmd->client, conn, 
1535                           "Usage: /OPER <username> [<public key>]");
1536     COMMAND_ERROR;
1537     goto out;
1538   }
1539
1540   if (cmd->argc == 3) {
1541     /* XXX Get public key */
1542     auth_data = NULL;
1543     COMMAND_ERROR;
1544     goto out;
1545   } else {
1546     /* Get passphrase */
1547
1548     auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1549     if (!auth_data) {
1550       COMMAND_ERROR;
1551       goto out;
1552     }
1553
1554     /* Encode the authentication payload */
1555     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1556                                     auth_data, strlen(auth_data));
1557   }
1558
1559   buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
1560                                           1, cmd->argv[1], 
1561                                           strlen(cmd->argv[1]),
1562                                           2, auth->data, auth->len);
1563   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1564                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1565
1566   silc_buffer_free(buffer);
1567   silc_buffer_free(auth);
1568   memset(auth_data, 0, strlen(auth_data));
1569   silc_free(auth_data);
1570
1571   /* Notify application */
1572   COMMAND;
1573
1574  out:
1575   silc_client_command_free(cmd);
1576 }
1577
1578 /* SILCOPER command. Used to obtain router operator privileges. */
1579
1580 SILC_CLIENT_CMD_FUNC(silcoper)
1581 {
1582   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1583   SilcClientConnection conn = cmd->conn;
1584   SilcBuffer buffer;
1585   unsigned char *auth_data;
1586   SilcBuffer auth;
1587
1588   if (!cmd->conn) {
1589     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1590     COMMAND_ERROR;
1591     goto out;
1592   }
1593
1594   if (cmd->argc < 2) {
1595     cmd->client->ops->say(cmd->client, conn, 
1596                           "Usage: /SILCOPER <username> [<public key>]");
1597     COMMAND_ERROR;
1598     goto out;
1599   }
1600
1601   if (cmd->argc == 3) {
1602     /* XXX Get public key */
1603     auth_data = NULL;
1604     COMMAND_ERROR;
1605     goto out;
1606   } else {
1607     /* Get passphrase */
1608
1609     auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1610     if (!auth_data) {
1611       COMMAND_ERROR;
1612       goto out;
1613     }
1614
1615     /* Encode the authentication payload */
1616     auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1617                                     auth_data, strlen(auth_data));
1618   }
1619
1620   buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
1621                                           1, cmd->argv[1], 
1622                                           strlen(cmd->argv[1]),
1623                                           2, auth->data, auth->len);
1624   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1625                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1626
1627   silc_buffer_free(buffer);
1628   silc_buffer_free(auth);
1629   memset(auth_data, 0, strlen(auth_data));
1630   silc_free(auth_data);
1631
1632   /* Notify application */
1633   COMMAND;
1634
1635  out:
1636   silc_client_command_free(cmd);
1637 }
1638
1639 /* CONNECT command. Connects the server to another server. */
1640
1641 SILC_CLIENT_CMD_FUNC(connect)
1642 {
1643   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1644   SilcClientConnection conn = cmd->conn;
1645   SilcBuffer buffer;
1646   unsigned char port[4];
1647   unsigned int tmp;
1648
1649   if (!cmd->conn) {
1650     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1651     COMMAND_ERROR;
1652     goto out;
1653   }
1654
1655   if (cmd->argc < 2) {
1656     cmd->client->ops->say(cmd->client, conn, 
1657                           "Usage: /CONNECT <server> [<port>]");
1658     COMMAND_ERROR;
1659     goto out;
1660   }
1661
1662   if (cmd->argc == 3) {
1663     tmp = atoi(cmd->argv[2]);
1664     SILC_PUT32_MSB(tmp, port);
1665   }
1666
1667   if (cmd->argc == 3)
1668     buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2, 
1669                                             1, cmd->argv[1], 
1670                                             strlen(cmd->argv[1]),
1671                                             2, port, 4);
1672   else
1673     buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1674                                             1, cmd->argv[1], 
1675                                             strlen(cmd->argv[1]));
1676   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1677                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1678   silc_buffer_free(buffer);
1679
1680   /* Notify application */
1681   COMMAND;
1682
1683  out:
1684   silc_client_command_free(cmd);
1685 }
1686
1687 SILC_CLIENT_CMD_FUNC(restart)
1688 {
1689 }
1690
1691 /* CLOSE command. Close server connection to the remote server */
1692  
1693 SILC_CLIENT_CMD_FUNC(close)
1694 {
1695   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1696   SilcClientConnection conn = cmd->conn;
1697   SilcBuffer buffer;
1698   unsigned char port[4];
1699   unsigned int tmp;
1700
1701   if (!cmd->conn) {
1702     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1703     COMMAND_ERROR;
1704     goto out;
1705   }
1706
1707   if (cmd->argc < 2) {
1708     cmd->client->ops->say(cmd->client, conn, 
1709                           "Usage: /CLOSE <server> [<port>]");
1710     COMMAND_ERROR;
1711     goto out;
1712   }
1713
1714   if (cmd->argc == 3) {
1715     tmp = atoi(cmd->argv[2]);
1716     SILC_PUT32_MSB(tmp, port);
1717   }
1718
1719   if (cmd->argc == 3)
1720     buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2, 
1721                                             1, cmd->argv[1], 
1722                                             strlen(cmd->argv[1]),
1723                                             2, port, 4);
1724   else
1725     buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1726                                             1, cmd->argv[1], 
1727                                             strlen(cmd->argv[1]));
1728   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1729                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1730   silc_buffer_free(buffer);
1731
1732   /* Notify application */
1733   COMMAND;
1734
1735  out:
1736   silc_client_command_free(cmd);
1737 }
1738  
1739 /* SHUTDOWN command. Shutdowns the server. */
1740
1741 SILC_CLIENT_CMD_FUNC(shutdown)
1742 {
1743   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1744
1745   if (!cmd->conn) {
1746     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1747     COMMAND_ERROR;
1748     goto out;
1749   }
1750
1751   /* Send the command */
1752   silc_client_send_command(cmd->client, cmd->conn, 
1753                            SILC_COMMAND_SHUTDOWN, 0, 0);
1754
1755   /* Notify application */
1756   COMMAND;
1757
1758  out:
1759   silc_client_command_free(cmd);
1760 }
1761  
1762 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1763
1764 SILC_CLIENT_CMD_FUNC(leave)
1765 {
1766   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1767   SilcClientConnection conn = cmd->conn;
1768   SilcIDCacheEntry id_cache = NULL;
1769   SilcChannelEntry channel;
1770   SilcBuffer buffer, idp;
1771   char *name;
1772
1773   if (!cmd->conn) {
1774     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1775     COMMAND_ERROR;
1776     goto out;
1777   }
1778
1779   if (cmd->argc != 2) {
1780     cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1781     COMMAND_ERROR;
1782     goto out;
1783   }
1784
1785   if (cmd->argv[1][0] == '*') {
1786     if (!conn->current_channel) {
1787       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1788       COMMAND_ERROR;
1789       goto out;
1790     }
1791     name = conn->current_channel->channel_name;
1792   } else {
1793     name = cmd->argv[1];
1794   }
1795
1796   if (!conn->current_channel) {
1797     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1798     COMMAND_ERROR;
1799     goto out;
1800   }
1801
1802   /* Get the Channel ID of the channel */
1803   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1804     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1805     COMMAND_ERROR;
1806     goto out;
1807   }
1808
1809   channel = (SilcChannelEntry)id_cache->context;
1810
1811   /* Send LEAVE command to the server */
1812   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1813   buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
1814                                           1, idp->data, idp->len);
1815   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
1816                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
1817   silc_buffer_free(buffer);
1818   silc_buffer_free(idp);
1819
1820   /* We won't talk anymore on this channel */
1821   cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1822
1823   conn->current_channel = NULL;
1824
1825   silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1826   silc_free(channel->channel_name);
1827   silc_free(channel->id);
1828   silc_free(channel->key);
1829   silc_cipher_free(channel->channel_key);
1830   silc_free(channel);
1831
1832   /* Notify application */
1833   COMMAND;
1834
1835  out:
1836   silc_client_command_free(cmd);
1837 }
1838
1839 /* Command USERS. Requests the USERS of the clients joined on requested
1840    channel. */
1841
1842 SILC_CLIENT_CMD_FUNC(users)
1843 {
1844   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1845   SilcClientConnection conn = cmd->conn;
1846   SilcIDCacheEntry id_cache = NULL;
1847   SilcChannelEntry channel;
1848   SilcBuffer buffer, idp;
1849   char *name, *line = NULL;
1850   unsigned int line_len = 0;
1851
1852   if (!cmd->conn) {
1853     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1854     COMMAND_ERROR;
1855     goto out;
1856   }
1857
1858   if (cmd->argc != 2) {
1859     cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1860     COMMAND_ERROR;
1861     goto out;
1862   }
1863
1864   if (cmd->argv[1][0] == '*') {
1865     if (!conn->current_channel) {
1866       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1867       COMMAND_ERROR;
1868       goto out;
1869     }
1870     name = conn->current_channel->channel_name;
1871   } else {
1872     name = cmd->argv[1];
1873   }
1874
1875   if (!conn->current_channel) {
1876     cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1877     COMMAND_ERROR;
1878     goto out;
1879   }
1880
1881   /* Get the Channel ID of the channel */
1882   if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1883     /* XXX should resolve the channel ID; LIST command */
1884     cmd->client->ops->say(cmd->client, conn, 
1885                           "You are not on that channel", name);
1886     COMMAND_ERROR;
1887     goto out;
1888   }
1889
1890   channel = (SilcChannelEntry)id_cache->context;
1891
1892   if (!cmd->pending) {
1893     /* Send USERS command to the server */
1894     idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1895     buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 
1896                                             ++conn->cmd_ident, 1, 
1897                                             1, idp->data, idp->len);
1898     silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
1899                             NULL, 0, NULL, NULL, buffer->data, 
1900                             buffer->len, TRUE);
1901     silc_buffer_free(buffer);
1902     silc_buffer_free(idp);
1903
1904     /* Register pending callback which will recall this command callback with
1905        same context and reprocesses the command. When reprocessing we actually
1906        display the information on the screen. */
1907     silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident, 
1908                                 silc_client_command_destructor,
1909                                 silc_client_command_users, 
1910                                 silc_client_command_dup(cmd));
1911     cmd->pending = TRUE;
1912     return;
1913   }
1914
1915   if (cmd->pending) {
1916     /* Pending command. Now we've resolved the information from server and
1917        we are ready to display the information on screen. */
1918     int i;
1919     SilcChannelUser chu;
1920
1921     cmd->client->ops->say(cmd->client, conn, "Users on %s", 
1922                           channel->channel_name);
1923
1924     line = silc_calloc(4096, sizeof(*line));
1925     line_len = 4096;
1926     silc_list_start(channel->clients);
1927     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1928       SilcClientEntry e = chu->client;
1929       char *m, tmp[80], len1;
1930
1931       memset(line, 0, sizeof(line_len));
1932
1933       if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1934         silc_free(line);
1935         line_len += strlen(e->nickname) + strlen(e->server) + 100;
1936         line = silc_calloc(line_len, sizeof(*line));
1937       }
1938
1939       memset(tmp, 0, sizeof(tmp));
1940       m = silc_client_chumode_char(chu->mode);
1941
1942       strncat(line, " ", 1);
1943       strncat(line, e->nickname, strlen(e->nickname));
1944       strncat(line, e->server ? "@" : "", 1);
1945
1946       len1 = 0;
1947       if (e->server)
1948         len1 = strlen(e->server);
1949       strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1950
1951       len1 = strlen(line);
1952       if (len1 >= 30) {
1953         memset(&line[29], 0, len1 - 29);
1954       } else {
1955         for (i = 0; i < 30 - len1 - 1; i++)
1956           strcat(line, " ");
1957       }
1958
1959       strncat(line, "  H", 3);
1960       strcat(tmp, m ? m : "");
1961       strncat(line, tmp, strlen(tmp));
1962
1963       if (strlen(tmp) < 5)
1964         for (i = 0; i < 5 - strlen(tmp); i++)
1965           strcat(line, " ");
1966
1967       strcat(line, e->username ? e->username : "");
1968
1969       cmd->client->ops->say(cmd->client, conn, "%s", line);
1970
1971       if (m)
1972         silc_free(m);
1973     }
1974   }
1975
1976   if (line)
1977     silc_free(line);
1978
1979   /* Notify application */
1980   COMMAND;
1981
1982  out:
1983   silc_client_command_free(cmd);
1984 }
1985
1986 /* Command BAN. This is used to manage the ban list of the channel. */
1987
1988 SILC_CLIENT_CMD_FUNC(ban)
1989 {
1990   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1991   SilcClientConnection conn = cmd->conn;
1992   SilcChannelEntry channel;
1993   SilcBuffer buffer, chidp;
1994   int type = 0;
1995   char *name, *ban = NULL;
1996
1997   if (!cmd->conn) {
1998     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1999     COMMAND_ERROR;
2000     goto out;
2001   }
2002
2003   if (cmd->argc < 2) {
2004     cmd->client->ops->say(cmd->client, conn, 
2005                    "Usage: /BAN <channel> "
2006                    "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
2007     COMMAND_ERROR;
2008     goto out;
2009   }
2010
2011   if (cmd->argv[1][0] == '*') {
2012     if (!conn->current_channel) {
2013       cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
2014       COMMAND_ERROR;
2015       goto out;
2016     }
2017
2018     channel = conn->current_channel;
2019   } else {
2020     name = cmd->argv[1];
2021
2022     channel = silc_client_get_channel(cmd->client, conn, name);
2023     if (!channel) {
2024       cmd->client->ops->say(cmd->client, conn, "You are on that channel");
2025       COMMAND_ERROR;
2026       goto out;
2027     }
2028   }
2029
2030   if (cmd->argc == 3) {
2031     if (cmd->argv[2][0] == '+')
2032       type = 2;
2033     else
2034       type = 3;
2035
2036     ban = cmd->argv[2];
2037     ban++;
2038   }
2039
2040   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2041
2042   /* Send the command */
2043   if (ban)
2044     buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2, 
2045                                             1, chidp->data, chidp->len,
2046                                             type, ban, strlen(ban));
2047   else
2048     buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1, 
2049                                             1, chidp->data, chidp->len);
2050
2051   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
2052                           0, NULL, NULL, buffer->data, buffer->len, TRUE);
2053   silc_buffer_free(buffer);
2054   silc_buffer_free(chidp);
2055
2056   /* Notify application */
2057   COMMAND;
2058
2059  out:
2060   silc_client_command_free(cmd);
2061 }