5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
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.
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.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
27 * Revision 1.1 2000/06/27 11:36:56 priikone
33 #include "clientincludes.h"
35 /* Client command reply list. */
36 SilcClientCommandReply silc_command_reply_list[] =
38 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
39 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
40 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
41 SILC_CLIENT_CMD_REPLY(nick, NICK),
42 SILC_CLIENT_CMD_REPLY(list, LIST),
43 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
44 SILC_CLIENT_CMD_REPLY(invite, INVITE),
45 SILC_CLIENT_CMD_REPLY(quit, QUIT),
46 SILC_CLIENT_CMD_REPLY(kill, KILL),
47 SILC_CLIENT_CMD_REPLY(info, INFO),
48 SILC_CLIENT_CMD_REPLY(away, AWAY),
49 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
50 SILC_CLIENT_CMD_REPLY(ping, PING),
51 SILC_CLIENT_CMD_REPLY(oper, OPER),
52 SILC_CLIENT_CMD_REPLY(join, JOIN),
53 SILC_CLIENT_CMD_REPLY(motd, MOTD),
54 SILC_CLIENT_CMD_REPLY(umode, UMODE),
55 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
56 SILC_CLIENT_CMD_REPLY(kick, KICK),
57 SILC_CLIENT_CMD_REPLY(restart, RESTART),
58 SILC_CLIENT_CMD_REPLY(close, CLOSE),
59 SILC_CLIENT_CMD_REPLY(die, DIE),
60 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
61 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
62 SILC_CLIENT_CMD_REPLY(names, LEAVE),
67 /* Status message structure. Messages are defined below. */
69 SilcCommandStatus status;
71 } SilcCommandStatusMessage;
73 /* Status messages returned by the server */
74 #define STAT(x) SILC_STATUS_ERR_##x
75 const SilcCommandStatusMessage silc_command_status_messages[] = {
77 { STAT(NO_SUCH_NICK), "No such nickname" },
78 { STAT(NO_SUCH_CHANNEL), "No such channel" },
79 { STAT(NO_SUCH_SERVER), "No such server" },
80 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
81 { STAT(NO_RECIPIENT), "No recipient given" },
82 { STAT(UNKNOWN_COMMAND), "Unknown command" },
83 { STAT(WILDCARDS), "Unknown command" },
84 { STAT(NO_CLIENT_ID), "No Client ID given" },
85 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
86 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
87 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
88 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
89 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
90 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
91 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
92 { STAT(USER_ON_CHANNEL), "User already on channel" },
93 { STAT(NOT_REGISTERED), "You have not registered" },
94 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
95 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
96 { STAT(PERM_DENIED), "Your host is not among the privileged" },
97 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
98 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
99 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
100 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
101 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
102 { STAT(UNKNOWN_MODE), "Unknown mode" },
103 { STAT(NOT_YOU), "Cannot change mode for other users" },
104 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
105 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
106 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
107 { STAT(BAD_NICKNAME), "Bad nickname" },
108 { STAT(BAD_CHANNEL), "Bad channel name" },
109 { STAT(AUTH_FAILED), "Authentication failed" },
114 /* Process received command reply. */
116 void silc_client_command_reply_process(SilcClient client,
117 SilcSocketConnection sock,
120 SilcClientCommandReplyContext ctx;
121 SilcCommandPayload payload;
123 /* Get command reply payload from packet */
124 payload = silc_command_parse_payload(buffer);
126 /* Silently ignore bad reply packet */
127 SILC_LOG_DEBUG(("Bad command reply packet"));
131 /* Allocate command reply context. This must be free'd by the
132 command reply routine receiving it. */
133 ctx = silc_calloc(1, sizeof(*ctx));
134 ctx->client = client;
136 ctx->payload = payload;
138 /* Check for pending commands and mark to be exeucted */
139 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
141 /* Execute command reply */
142 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
145 /* Returns status message string */
148 silc_client_command_status_message(SilcCommandStatus status)
152 for (i = 0; silc_command_status_messages[i].message; i++) {
153 if (silc_command_status_messages[i].status == status)
157 if (silc_command_status_messages[i].message == NULL)
160 return silc_command_status_messages[i].message;
163 /* Free command reply context and its internals. */
165 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
168 silc_command_free_payload(cmd->payload);
173 /* Received reply for WHOIS command. This maybe called several times
174 for one WHOIS command as server may reply with list of results. */
176 SILC_CLIENT_CMD_REPLY_FUNC(whois)
178 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
179 SilcClient client = cmd->client;
180 SilcCommandStatus status;
183 SILC_LOG_DEBUG(("Start"));
185 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
186 SILC_GET16_MSB(status, tmp);
187 if (status != SILC_STATUS_OK) {
188 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
190 silc_say(cmd->client, "%s: %s", tmp,
191 silc_client_command_status_message(status));
194 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
199 /* Display one whois reply */
200 if (status == SILC_STATUS_OK) {
203 unsigned char *id_data;
204 char *nickname = NULL, *username = NULL;
205 char *realname = NULL;
208 memset(buf, 0, sizeof(buf));
210 argc = silc_command_get_arg_num(cmd->payload);
211 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
213 nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
215 strncat(buf, nickname, len);
216 strncat(buf, " is ", 4);
219 username = silc_command_get_arg_type(cmd->payload, 4, &len);
221 strncat(buf, username, len);
224 realname = silc_command_get_arg_type(cmd->payload, 5, &len);
226 strncat(buf, " (", 2);
227 strncat(buf, realname, len);
228 strncat(buf, ")", 1);
232 /* Save received Client ID to ID cache */
233 /* XXX Maybe should not be saved as /MSG will get confused */
234 id = silc_id_str2id(id_data, SILC_ID_CLIENT);
235 client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
236 silc_idcache_add(&client->current_win->
237 client_id_cache[(int)nickname[0] - 32],
238 client->current_win->
239 client_id_cache_count[(int)nickname[0] - 32],
240 strdup(nickname), SILC_ID_CLIENT, id, NULL);
243 silc_say(cmd->client, "%s", buf);
246 if (status == SILC_STATUS_LIST_START) {
250 if (status == SILC_STATUS_LIST_END) {
254 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
257 silc_client_command_reply_free(cmd);
260 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
264 /* Received reply for IDENTIFY command. This maybe called several times
265 for one IDENTIFY command as server may reply with list of results.
266 This is totally silent and does not print anything on screen. */
268 SILC_CLIENT_CMD_REPLY_FUNC(identify)
270 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
271 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
272 SilcClientEntry client_entry;
273 SilcCommandStatus status;
276 SILC_LOG_DEBUG(("Start"));
278 #define CIDC(x) win->client_id_cache[(x) - 32]
279 #define CIDCC(x) win->client_id_cache_count[(x) - 32]
281 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
282 SILC_GET16_MSB(status, tmp);
283 if (status != SILC_STATUS_OK) {
284 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
286 silc_say(cmd->client, "%s: %s", tmp,
287 silc_client_command_status_message(status));
290 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
295 /* Display one whois reply */
296 if (status == SILC_STATUS_OK) {
297 unsigned char *id_data;
300 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
301 nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
303 /* Allocate client entry */
304 client_entry = silc_calloc(1, sizeof(*client_entry));
305 client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
306 client_entry->nickname = strdup(nickname);
308 /* Save received Client ID to ID cache */
310 silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
311 client_entry->nickname, SILC_ID_CLIENT,
312 client_entry->id, client_entry);
315 if (status == SILC_STATUS_LIST_START) {
319 if (status == SILC_STATUS_LIST_END) {
323 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
326 silc_client_command_reply_free(cmd);
331 /* Received reply for command NICK. If everything went without errors
332 we just received our new Client ID. */
334 SILC_CLIENT_CMD_REPLY_FUNC(nick)
336 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
337 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
338 SilcCommandStatus status;
339 unsigned char *tmp, *id_string;
342 SILC_LOG_DEBUG(("Start"));
344 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
345 SILC_GET16_MSB(status, tmp);
346 if (status != SILC_STATUS_OK) {
347 silc_say(cmd->client, "Cannot set nickname: %s",
348 silc_client_command_status_message(status));
352 argc = silc_command_get_arg_num(cmd->payload);
353 if (argc < 2 || argc > 2) {
354 silc_say(cmd->client, "Cannot set nickname: bad reply to command");
358 /* Take received Client ID */
359 id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
360 silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
362 /* Update nickname on screen */
363 cmd->client->screen->bottom_line->nickname = win->nickname;
364 silc_screen_print_bottom_line(cmd->client->screen, 0);
367 silc_client_command_reply_free(cmd);
370 SILC_CLIENT_CMD_REPLY_FUNC(list)
374 SILC_CLIENT_CMD_REPLY_FUNC(topic)
378 SILC_CLIENT_CMD_REPLY_FUNC(invite)
382 SILC_CLIENT_CMD_REPLY_FUNC(quit)
386 SILC_CLIENT_CMD_REPLY_FUNC(kill)
390 SILC_CLIENT_CMD_REPLY_FUNC(info)
394 SILC_CLIENT_CMD_REPLY_FUNC(away)
398 SILC_CLIENT_CMD_REPLY_FUNC(connect)
402 SILC_CLIENT_CMD_REPLY_FUNC(ping)
406 SILC_CLIENT_CMD_REPLY_FUNC(oper)
410 /* Received reply for JOIN command. */
412 SILC_CLIENT_CMD_REPLY_FUNC(join)
414 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
415 SilcClient client = cmd->client;
416 SilcCommandStatus status;
418 unsigned char *id_string;
419 char *topic, *tmp, *channel_name;
421 SILC_LOG_DEBUG(("Start"));
423 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
424 SILC_GET16_MSB(status, tmp);
425 if (status != SILC_STATUS_OK) {
426 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
430 argc = silc_command_get_arg_num(cmd->payload);
431 if (argc < 3 || argc > 4) {
432 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
436 /* Get channel name */
437 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
438 channel_name = strdup(tmp);
441 id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
444 topic = silc_command_get_arg_type(cmd->payload, 4, NULL);
446 /* Save received Channel ID */
447 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, id_string);
449 /* Print channel name on screen */
450 client->screen->bottom_line->channel = channel_name;
451 silc_screen_print_bottom_line(client->screen, 0);
454 silc_say(client, "Topic for %s: %s", channel_name, topic);
457 silc_client_command_reply_free(cmd);
460 SILC_CLIENT_CMD_REPLY_FUNC(motd)
464 SILC_CLIENT_CMD_REPLY_FUNC(umode)
468 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
472 SILC_CLIENT_CMD_REPLY_FUNC(kick)
476 SILC_CLIENT_CMD_REPLY_FUNC(restart)
480 SILC_CLIENT_CMD_REPLY_FUNC(close)
484 SILC_CLIENT_CMD_REPLY_FUNC(die)
488 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
492 SILC_CLIENT_CMD_REPLY_FUNC(leave)
496 SILC_CLIENT_CMD_REPLY_FUNC(names)
500 /* Private message received. This processes the private message and
501 finally displays it on the screen. */
503 SILC_CLIENT_CMD_REPLY_FUNC(msg)
505 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
506 SilcClient client = cmd->client;
507 SilcBuffer buffer = (SilcBuffer)cmd->context;
508 unsigned short nick_len;
509 unsigned char *nickname, *message;
510 SilcIDCache *id_cache;
511 unsigned char *id_string;
515 silc_buffer_unformat(buffer,
516 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
518 silc_buffer_pull(buffer, 2 + nick_len);
521 /* Get ID of the sender */
522 id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
523 silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
524 memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
525 silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
526 id = silc_id_str2id(id_string, SILC_ID_CLIENT);
527 silc_free(id_string);
529 /* Nickname should be verified if we don't have it in the cache */
530 if (silc_idcache_find_by_data(client->current_win->
531 client_id_cache[nickname[0] - 32],
532 client->current_win->
533 client_id_cache_count[nickname[0] - 32],
534 nickname, &id_cache) == FALSE) {
536 SilcClientCommandContext ctx;
539 /* Private message from unknown source, try to resolve it. */
546 message = silc_calloc(buffer->len + 1, sizeof(char));
547 memcpy(message, buffer->data, buffer->len);
548 silc_print(client, "*%s* %s", nickname, message);
549 memset(message, 0, buffer->len);