1 /*
2
3 local_command.c
4
5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7 Copyright (C) 1997 - 2000 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: local_command.c,v 1.21 2002/02/24 11:14:43 priikone Exp $ */
21
22 #include "clientincludes.h"
23 #include "client_internal.h"
24
25 /* Local commands. */
26 SilcClientCommand silc_local_command_list[] =
27 {
28 SILC_CLIENT_LCMD(help, HELP, "HELP", 0, 2),
29 SILC_CLIENT_LCMD(clear, CLEAR, "CLEAR", 0, 1),
30 SILC_CLIENT_LCMD(version, VERSION, "VERSION", 0, 1),
31 SILC_CLIENT_LCMD(server, SERVER, "SERVER", 0, 2),
32 SILC_CLIENT_LCMD(msg, MSG, "MSG", 0, 3),
33 SILC_CLIENT_LCMD(away, AWAY, "AWAY", 0, 2),
34 SILC_CLIENT_LCMD(key, KEY, "KEY", 0, 7),
35 SILC_CLIENT_LCMD(me, ME, "ME", 0, 3),
36 SILC_CLIENT_LCMD(notice, NOTICE, "NOTICE", 0, 3),
37
38 { NULL, 0, NULL, 0, 0 },
39 };
40
41 /* Finds and returns a pointer to the command list. Return NULL if the
42 command is not found. */
43
44 SilcClientCommand *silc_client_local_command_find(const char *name)
45 {
46 SilcClientCommand *cmd;
47
48 for (cmd = silc_local_command_list; cmd->name; cmd++) {
49 if (!strcmp(cmd->name, name))
50 return cmd;
51 }
52
53 return NULL;
54 }
55
56 /* HELP command. This is local command and shows help on SILC */
57
58 SILC_CLIENT_LCMD_FUNC(help)
59 {
60
61 }
62
63 /* CLEAR command. This is local command and clears current output window */
64
65 SILC_CLIENT_LCMD_FUNC(clear)
66 {
67 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
68
69 silc_client_command_free(cmd);
70 }
71
72 /* VERSION command. This is local command and shows version of the client */
73
74 SILC_CLIENT_LCMD_FUNC(version)
75 {
76 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
77 SilcClient client = cmd->client;
78 extern char *silc_version;
79 extern char *silc_name;
80 extern char *silc_fullname;
81
82 silc_say(client, cmd->conn,
83 "%s (%s) version %s", silc_name, silc_fullname,
84 silc_version);
85
86 silc_client_command_free(cmd);
87 }
88
89 /* Command MSG. Sends private message to user or list of users. Note that
90 private messages are not really commands, they are message packets,
91 however, on user interface it is convenient to show them as commands
92 as that is the common way of sending private messages (like in IRC). */
93
94 SILC_CLIENT_LCMD_FUNC(msg)
95 {
96 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
97 SilcClientConnection conn = cmd->conn;
98 SilcClient client = cmd->client;
99 SilcClientEntry client_entry = NULL;
100 SilcUInt32 num = 0;
101 char *nickname = NULL, *server = NULL;
102
103 if (!cmd->conn) {
104 silc_say(client, conn,
105 "You are not connected to a server, use /SERVER to connect");
106 goto out;
107 }
108
109 if (cmd->argc < 3) {
110 silc_say(client, conn, "Usage: /MSG <nickname> <message>");
111 goto out;
112 }
113
114 /* Parse the typed nickname. */
115 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
116 silc_say(client, conn, "Bad nickname");
117 goto out;
118 }
119
120 /* Find client entry */
121 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
122 TRUE);
123 if (!client_entry) {
124 /* Client entry not found, it was requested thus mark this to be
125 pending command. */
126 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
127 NULL, silc_client_local_command_msg, context);
128 return;
129 }
130
131 /* Display the message for our eyes. */
132 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
133
134 /* Send the private message */
135 silc_client_send_private_message(client, conn, client_entry, 0,
136 cmd->argv[2], cmd->argv_lens[2],
137 TRUE);
138
139 out:
140 silc_client_command_free(cmd);
141 }
142
143
144 /* Command SERVER. Connects to remote SILC server. This is local command. */
145
146 SILC_CLIENT_LCMD_FUNC(server)
147 {
148 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
149 SilcClient client = cmd->client;
150 SilcClientConnection conn = cmd->conn;
151 int i = 0, len, port;
152 char *hostname;
153
154 if (cmd->argc < 2) {
155 /* Show current servers */
156
157 if (!cmd->conn) {
158 silc_say(client, conn, "You are not connected to any server");
159 silc_say(client, conn, "Usage: /SERVER [<server>[:<port>]]");
160 goto out;
161 }
162
163 silc_say(client, conn, "Current server: %s on %d %s",
164 conn->remote_host, conn->remote_port,
165 conn->remote_info ? conn->remote_info : "");
166
167 silc_say(client, conn, "Server list:");
168 for (i = 0; i < client->conns_count; i++) {
169 silc_say(client, conn, " [%d] %s on %d %s", i + 1,
170 client->conns[i]->remote_host,
171 client->conns[i]->remote_port,
172 client->conns[i]->remote_info ?
173 client->conns[i]->remote_info : "");
174 }
175
176 goto out;
177 }
178
179 /* See if port is included and then extract it */
180 if (strchr(cmd->argv[1], ':')) {
181 len = strcspn(cmd->argv[1], ":");
182 hostname = silc_calloc(len + 1, sizeof(char));
183 memcpy(hostname, cmd->argv[1], len);
184 port = atoi(cmd->argv[1] + 1 + len);
185 } else {
186 hostname = cmd->argv[1];
187 port = 706;
188 }
189
190 #if 0
191 if (conn && conn->remote_host) {
192 if (!strcmp(hostname, conn->remote_host) && port == conn->remote_port) {
193 silc_say(client, conn, "You are already connected to that server");
194 goto out;
195 }
196
197 /* Close connection */
198 cmd->client->ops->disconnect(cmd->client, cmd->conn);
199 silc_client_close_connection(cmd->client, cmd->conn->sock);
200 }
201 #endif
202
203 /* Connect asynchronously to not to block user interface */
204 silc_client_connect_to_server(cmd->client, port, hostname, NULL);
205
206 out:
207 silc_client_command_free(cmd);
208 }
209
210 /* Local command AWAY. Client replies with away message to whomever sends
211 private message to the client if the away message is set. If this is
212 given without arguments the away message is removed. */
213
214 SILC_CLIENT_LCMD_FUNC(away)
215 {
216 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
217 SilcClientConnection conn = cmd->conn;
218 SilcClient client = cmd->client;
219 SilcClientInternal app = (SilcClientInternal)client->application;
220 unsigned char modebuf[4];
221 SilcBuffer idp, buffer;
222
223 if (!cmd->conn) {
224 silc_say(client, conn,
225 "You are not connected to a server, use /SERVER to connect");
226 goto out;
227 }
228
229 if (cmd->argc == 1) {
230 conn->local_entry->mode &= ~SILC_UMODE_GONE;
231
232 if (conn->away) {
233 silc_free(conn->away->away);
234 silc_free(conn->away);
235 conn->away = NULL;
236 app->screen->bottom_line->away = FALSE;
237
238 silc_say(client, conn, "Away message removed");
239 silc_screen_print_bottom_line(app->screen, 0);
240 }
241 } else {
242 conn->local_entry->mode |= SILC_UMODE_GONE;
243
244 if (conn->away)
245 silc_free(conn->away->away);
246 else
247 conn->away = silc_calloc(1, sizeof(*conn->away));
248
249 app->screen->bottom_line->away = TRUE;
250 conn->away->away = strdup(cmd->argv[1]);
251
252 silc_say(client, conn, "Away message set: %s", conn->away->away);
253 silc_screen_print_bottom_line(app->screen, 0);
254 }
255
256 /* Send the UMODE command to se myself as gone */
257 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
258 SILC_PUT32_MSB(conn->local_entry->mode, modebuf);
259 buffer = silc_command_payload_encode_va(SILC_COMMAND_UMODE,
260 ++conn->cmd_ident, 2,
261 1, idp->data, idp->len,
262 2, modebuf, sizeof(modebuf));
263 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
264 NULL, 0, NULL, NULL, buffer->data,
265 buffer->len, TRUE);
266 silc_buffer_free(buffer);
267 silc_buffer_free(idp);
268
269 out:
270 silc_client_command_free(cmd);
271 }
272
273 typedef struct {
274 int type; /* 1 = msg, 2 = channel */
275 } *KeyInternal;
276
277 static SilcSKEKeyMaterial *curr_key = NULL;
278
279 /* Key agreement callback that is called after the key agreement protocol
280 has been performed. This is called also if error occured during the
281 key agreement protocol. The `key' is the allocated key material and
282 the caller is responsible of freeing it. The `key' is NULL if error
283 has occured. The application can freely use the `key' to whatever
284 purpose it needs. See lib/silcske/silcske.h for the definition of
285 the SilcSKEKeyMaterial structure. */
286
287 static void keyagr_completion(SilcClient client,
288 SilcClientConnection conn,
289 SilcClientEntry client_entry,
290 SilcKeyAgreementStatus status,
291 SilcSKEKeyMaterial *key,
292 void *context)
293 {
294 KeyInternal i = (KeyInternal)context;
295
296 curr_key = NULL;
297
298 switch(status) {
299 case SILC_KEY_AGREEMENT_OK:
300 silc_say(client, conn, "Key agreement compeleted successfully with %s",
301 client_entry->nickname);;
302
303 if (i->type == 1) {
304 /* Set the private key for this client */
305 silc_client_del_private_message_key(client, conn, client_entry);
306 silc_client_add_private_message_key_ske(client, conn, client_entry,
307 NULL, key, FALSE);
308 silc_say(client, conn, "The private messages with the %s are now protected with the private key", client_entry->nickname);
309 silc_ske_free_key_material(key);
310 }
311
312 break;
313
314 case SILC_KEY_AGREEMENT_ERROR:
315 silc_say(client, conn, "Error occured during key agreement with %s",
316 client_entry->nickname);
317 break;
318
319 case SILC_KEY_AGREEMENT_FAILURE:
320 silc_say(client, conn, "The key agreement failed with %s",
321 client_entry->nickname);
322 break;
323
324 case SILC_KEY_AGREEMENT_TIMEOUT:
325 silc_say(client, conn, "Timeout during key agreement. The key agreement was not performed with %s",
326 client_entry->nickname);
327 break;
328
329 default:
330 break;
331 }
332
333 if (i)
334 silc_free(i);
335 }
336
337 /* Local command KEY. This command is used to set and unset private
338 keys for channels, set and unset private keys for private messages
339 with remote clients and to send key agreement requests and
340 negotiate the key agreement protocol with remote client. The
341 key agreement is supported only to negotiate private message keys,
342 it currently cannot be used to negotiate private keys for channels,
343 as it is not convenient for that purpose. */
344
345 SILC_CLIENT_LCMD_FUNC(key)
346 {
347 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
348 SilcClientConnection conn = cmd->conn;
349 SilcClient client = cmd->client;
350 SilcClientEntry client_entry = NULL;
351 SilcChannelEntry channel_entry = NULL;
352 SilcUInt32 num = 0;
353 char *nickname = NULL, *server = NULL;
354 int command = 0, port = 0, type = 0;
355 char *hostname = NULL;
356 KeyInternal internal = NULL;
357
358 if (!cmd->conn) {
359 silc_say(client, conn,
360 "You are not connected to a server, use /SERVER to connect");
361 goto out;
362 }
363
364 if (cmd->argc < 4) {
365 silc_say(client, conn, "Usage: /KEY msg|channel <nickname|channel> "
366 "set|unset|agreement|negotiate [<arguments>]");
367 goto out;
368 }
369
370 /* Get type */
371 if (!strcasecmp(cmd->argv[1], "msg"))
372 type = 1;
373 if (!strcasecmp(cmd->argv[1], "channel"))
374 type = 2;
375
376 if (type == 0) {
377 silc_say(client, conn, "Usage: /KEY msg|channel <nickname|channel> "
378 "set|unset|agreement|negotiate [<arguments>]");
379 goto out;
380 }
381
382 if (type == 1) {
383 if (cmd->argv[2][0] == '*') {
384 nickname = "*";
385 } else {
386 /* Parse the typed nickname. */
387 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
388 silc_say(client, conn, "Bad nickname");
389 goto out;
390 }
391
392 /* Find client entry */
393 client_entry = silc_idlist_get_client(client, conn, nickname,
394 server, num, TRUE);
395 if (!client_entry) {
396 /* Client entry not found, it was requested thus mark this to be
397 pending command. */
398 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
399 conn->cmd_ident,
400 NULL, silc_client_local_command_key,
401 context);
402 return;
403 }
404 }
405 }
406
407 if (type == 2) {
408 /* Get channel entry */
409 char *name;
410
411 if (cmd->argv[2][0] == '*') {
412 if (!conn->current_channel) {
413 silc_say(cmd->client, conn, "You are not on any channel");
414 goto out;
415 }
416 name = conn->current_channel->channel_name;
417 } else {
418 name = cmd->argv[2];
419 }
420
421 channel_entry = silc_client_get_channel(client, conn, name);
422 if (!channel_entry) {
423 silc_say(client, conn, "You are not on that channel");
424 goto out;
425 }
426 }
427
428 /* Set command */
429 if (!strcasecmp(cmd->argv[3], "set")) {
430 command = 1;
431
432 if (cmd->argc == 4) {
433 if (curr_key && type == 1 && client_entry) {
434 silc_client_del_private_message_key(client, conn, client_entry);
435 silc_client_add_private_message_key_ske(client, conn, client_entry,
436 NULL, curr_key, FALSE);
437 goto out;
438 }
439 }
440
441 if (cmd->argc >= 5) {
442 if (type == 1 && client_entry) {
443 /* Set private message key */
444
445 silc_client_del_private_message_key(client, conn, client_entry);
446
447 if (cmd->argc >= 6)
448 silc_client_add_private_message_key(client, conn, client_entry,
449 cmd->argv[5], cmd->argv[4],
450 cmd->argv_lens[4],
451 (cmd->argv[4][0] == '*' ?
452 TRUE : FALSE), FALSE);
453 else
454 silc_client_add_private_message_key(client, conn, client_entry,
455 NULL, cmd->argv[4],
456 cmd->argv_lens[4],
457 (cmd->argv[4][0] == '*' ?
458 TRUE : FALSE), FALSE);
459
460 /* Send the key to the remote client so that it starts using it
461 too. */
462 silc_client_send_private_message_key(client, conn, client_entry, TRUE);
463 } else if (type == 2) {
464 /* Set private channel key */
465 char *cipher = NULL, *hmac = NULL;
466
467 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
468 silc_say(client, conn,
469 "Private key mode is not set on this channel");
470 goto out;
471 }
472
473 if (cmd->argc >= 6)
474 cipher = cmd->argv[5];
475 if (cmd->argc >= 7)
476 hmac = cmd->argv[6];
477
478 if (!silc_client_add_channel_private_key(client, conn, channel_entry,
479 cipher, hmac,
480 cmd->argv[4],
481 cmd->argv_lens[4])) {
482 silc_say(client, conn, "Could not add channel private key");
483 goto out;
484 }
485 }
486 }
487
488 goto out;
489 }
490
491 /* Unset command */
492 if (!strcasecmp(cmd->argv[3], "unset")) {
493 command = 2;
494
495 if (type == 1 && client_entry) {
496 /* Unset private message key */
497 silc_client_del_private_message_key(client, conn, client_entry);
498 } else if (type == 2) {
499 /* Unset channel key(s) */
500 SilcChannelPrivateKey *keys;
501 SilcUInt32 keys_count;
502 int number;
503
504 if (cmd->argc == 4)
505 silc_client_del_channel_private_keys(client, conn, channel_entry);
506
507 if (cmd->argc > 4) {
508 number = atoi(cmd->argv[4]);
509 keys = silc_client_list_channel_private_keys(client, conn,
510 channel_entry,
511 &keys_count);
512 if (!keys)
513 goto out;
514
515 if (!number || number > keys_count) {
516 silc_client_free_channel_private_keys(keys, keys_count);
517 goto out;
518 }
519
520 silc_client_del_channel_private_key(client, conn, channel_entry,
521 keys[number - 1]);
522 silc_client_free_channel_private_keys(keys, keys_count);
523 }
524
525 goto out;
526 }
527 }
528
529 /* List command */
530 if (!strcasecmp(cmd->argv[3], "list")) {
531 command = 3;
532
533 if (type == 1) {
534 SilcPrivateMessageKeys keys;
535 SilcUInt32 keys_count;
536 int k, i, len;
537 char buf[1024];
538
539 keys = silc_client_list_private_message_keys(client, conn,
540 &keys_count);
541 if (!keys)
542 goto out;
543
544 /* list the private message key(s) */
545 if (nickname[0] == '*') {
546 silc_say(client, conn, "Private message keys");
547 silc_say(client, conn,
548 " Client Cipher Key");
549 for (k = 0; k < keys_count; k++) {
550 memset(buf, 0, sizeof(buf));
551 strncat(buf, " ", 2);
552 len = strlen(keys[k].client_entry->nickname);
553 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
554 if (len < 30)
555 for (i = 0; i < 30 - len; i++)
556 strcat(buf, " ");
557 strcat(buf, " ");
558
559 len = strlen(keys[k].cipher);
560 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
561 if (len < 14)
562 for (i = 0; i < 14 - len; i++)
563 strcat(buf, " ");
564 strcat(buf, " ");
565
566 if (keys[k].key)
567 strcat(buf, "<hidden>");
568 else
569 strcat(buf, "*generated*");
570
571 silc_say(client, conn, "%s", buf);
572 }
573 } else {
574 silc_say(client, conn, "Private message key",
575 client_entry->nickname);
576 silc_say(client, conn,
577 " Client Cipher Key");
578 for (k = 0; k < keys_count; k++) {
579 if (keys[k].client_entry != client_entry)
580 continue;
581
582 memset(buf, 0, sizeof(buf));
583 strncat(buf, " ", 2);
584 len = strlen(keys[k].client_entry->nickname);
585 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
586 if (len < 30)
587 for (i = 0; i < 30 - len; i++)
588 strcat(buf, " ");
589 strcat(buf, " ");
590
591 len = strlen(keys[k].cipher);
592 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
593 if (len < 14)
594 for (i = 0; i < 14 - len; i++)
595 strcat(buf, " ");
596 strcat(buf, " ");
597
598 if (keys[k].key)
599 strcat(buf, "<hidden>");
600 else
601 strcat(buf, "*generated*");
602
603 silc_say(client, conn, "%s", buf);
604 }
605 }
606
607 silc_client_free_private_message_keys(keys, keys_count);
608 } else if (type == 2) {
609 SilcChannelPrivateKey *keys;
610 SilcUInt32 keys_count;
611 int k, i, len;
612 char buf[1024];
613
614 keys = silc_client_list_channel_private_keys(client, conn, channel_entry,
615 &keys_count);
616 if (!keys)
617 goto out;
618
619 silc_say(client, conn, "Channel %s private keys",
620 channel_entry->channel_name);
621 silc_say(client, conn,
622 " Cipher Hmac Key");
623 for (k = 0; k < keys_count; k++) {
624 memset(buf, 0, sizeof(buf));
625 strncat(buf, " ", 2);
626
627 len = strlen(keys[k]->cipher->cipher->name);
628 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
629 if (len < 16)
630 for (i = 0; i < 16 - len; i++)
631 strcat(buf, " ");
632 strcat(buf, " ");
633
634 len = strlen(keys[k]->hmac->hmac->name);
635 strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
636 if (len < 16)
637 for (i = 0; i < 16 - len; i++)
638 strcat(buf, " ");
639 strcat(buf, " ");
640
641 strcat(buf, "<hidden>");
642
643 silc_say(client, conn, "%s", buf);
644 }
645
646 silc_client_free_channel_private_keys(keys, keys_count);
647 }
648
649 goto out;
650 }
651
652 /* Send command is used to send key agreement */
653 if (!strcasecmp(cmd->argv[3], "agreement")) {
654 command = 4;
655
656 if (cmd->argc >= 5)
657 hostname = cmd->argv[4];
658 if (cmd->argc >= 6)
659 port = atoi(cmd->argv[5]);
660
661 internal = silc_calloc(1, sizeof(*internal));
662 internal->type = type;
663 }
664
665 /* Start command is used to start key agreement (after receiving the
666 key_agreement client operation). */
667 if (!strcasecmp(cmd->argv[3], "negotiate")) {
668 command = 5;
669
670 if (cmd->argc >= 5)
671 hostname = cmd->argv[4];
672 if (cmd->argc >= 6)
673 port = atoi(cmd->argv[5]);
674
675 internal = silc_calloc(1, sizeof(*internal));
676 internal->type = type;
677 }
678
679 if (command == 0) {
680 silc_say(client, conn, "Usage: /KEY msg|channel <nickname|channel> "
681 "set|unset|agreement|negotiate [<arguments>]");
682 goto out;
683 }
684
685 if (command == 4 && client_entry) {
686 silc_say(client, conn, "Sending key agreement to %s", cmd->argv[2]);
687 silc_client_send_key_agreement(client, conn, client_entry, hostname,
688 port, 120, keyagr_completion, internal);
689 goto out;
690 }
691
692 if (command == 5 && client_entry) {
693 silc_say(client, conn, "Starting key agreement with %s", cmd->argv[2]);
694 silc_client_perform_key_agreement(client, conn, client_entry, hostname,
695 port, keyagr_completion, internal);
696 goto out;
697 }
698
699 out:
700 if (nickname)
701 silc_free(nickname);
702 if (server)
703 silc_free(server);
704 silc_client_command_free(cmd);
705 }
706
707 /* Sends an action to the channel. Equals CTCP's ACTION (IRC's /ME)
708 command. */
709
710 SILC_CLIENT_LCMD_FUNC(me)
711 {
712 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
713 SilcClientConnection conn = cmd->conn;
714 SilcClient client = cmd->client;
715 SilcChannelEntry channel_entry;
716 char *name;
717
718 if (!cmd->conn) {
719 silc_say(client, conn,
720 "You are not connected to a server, use /SERVER to connect");
721 goto out;
722 }
723
724 if (cmd->argc < 3) {
725 silc_say(client, conn, "Usage: /ME <channel> <action message>");
726 goto out;
727 }
728
729 if (cmd->argv[1][0] == '*') {
730 if (!conn->current_channel) {
731 silc_say(cmd->client, conn, "You are not on any channel");
732 goto out;
733 }
734 name = conn->current_channel->channel_name;
735 } else {
736 name = cmd->argv[1];
737 }
738
739 channel_entry = silc_client_get_channel(client, conn, name);
740 if (!channel_entry) {
741 silc_say(client, conn, "You are not on that channel");
742 goto out;
743 }
744
745 /* Send the action message */
746 silc_client_send_channel_message(client, conn, channel_entry, NULL,
747 SILC_MESSAGE_FLAG_ACTION,
748 cmd->argv[2], cmd->argv_lens[2], TRUE);
749
750 silc_print(client, "* %s %s", conn->nickname, cmd->argv[2]);
751
752 out:
753 silc_client_command_free(cmd);
754 }
755
756 /* Sends an notice to the channel. */
757
758 SILC_CLIENT_LCMD_FUNC(notice)
759 {
760 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
761 SilcClientConnection conn = cmd->conn;
762 SilcClient client = cmd->client;
763 SilcChannelEntry channel_entry;
764 char *name;
765
766 if (!cmd->conn) {
767 silc_say(client, conn,
768 "You are not connected to a server, use /SERVER to connect");
769 goto out;
770 }
771
772 if (cmd->argc < 3) {
773 silc_say(client, conn, "Usage: /NOTICE <channel> <message>");
774 goto out;
775 }
776
777 if (cmd->argv[1][0] == '*') {
778 if (!conn->current_channel) {
779 silc_say(cmd->client, conn, "You are not on any channel");
780 goto out;
781 }
782 name = conn->current_channel->channel_name;
783 } else {
784 name = cmd->argv[1];
785 }
786
787 channel_entry = silc_client_get_channel(client, conn, name);
788 if (!channel_entry) {
789 silc_say(client, conn, "You are not on that channel");
790 goto out;
791 }
792
793 /* Send the action message */
794 silc_client_send_channel_message(client, conn, channel_entry, NULL,
795 SILC_MESSAGE_FLAG_NOTICE,
796 cmd->argv[2], cmd->argv_lens[2], TRUE);
797
798 silc_print(client, "- %s %s", conn->nickname, cmd->argv[2]);
799
800 out:
801 silc_client_command_free(cmd);
802 }
803
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse