MInor typo fixes
[silc.git] / apps / silcd / command_reply.c
1 /*
2
3   command_reply.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$ */
21
22 #include "serverincludes.h"
23 #include "server_internal.h"
24 #include "command_reply.h"
25
26 #define COMMAND_CHECK_STATUS                                              \
27 do {                                                                      \
28   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
29   if (status != SILC_STATUS_OK) {                                         \
30     silc_server_command_reply_free(cmd);                                  \
31     return;                                                               \
32   }                                                                       \
33 } while(0)
34
35 #define COMMAND_CHECK_STATUS_LIST                                         \
36 do {                                                                      \
37   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
38   if (status != SILC_STATUS_OK &&                                         \
39       status != SILC_STATUS_LIST_START &&                                 \
40       status != SILC_STATUS_LIST_ITEM &&                                  \
41       status != SILC_STATUS_LIST_END) {                                   \
42     silc_server_command_reply_free(cmd);                                  \
43     return;                                                               \
44   }                                                                       \
45 } while(0)
46
47 /* Server command reply list. Not all commands have reply function as
48    they are never sent by server. More maybe added later if need appears. */
49 SilcServerCommandReply silc_command_reply_list[] =
50 {
51   SILC_SERVER_CMD_REPLY(join, JOIN),
52   SILC_SERVER_CMD_REPLY(identify, WHOIS),
53   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
54
55   { NULL, 0 },
56 };
57
58 /* Process received command reply. */
59
60 void silc_server_command_reply_process(SilcServer server,
61                                        SilcSocketConnection sock,
62                                        SilcBuffer buffer)
63 {
64   SilcServerCommandReply *cmd;
65   SilcServerCommandReplyContext ctx;
66   SilcCommandPayload payload;
67   SilcCommand command;
68   unsigned short ident;
69
70   SILC_LOG_DEBUG(("Start"));
71
72   /* Get command reply payload from packet */
73   payload = silc_command_payload_parse(buffer);
74   if (!payload) {
75     /* Silently ignore bad reply packet */
76     SILC_LOG_DEBUG(("Bad command reply packet"));
77     return;
78   }
79   
80   /* Allocate command reply context. This must be free'd by the
81      command reply routine receiving it. */
82   ctx = silc_calloc(1, sizeof(*ctx));
83   ctx->server = server;
84   ctx->sock = sock;
85   ctx->payload = payload;
86   ctx->args = silc_command_get_args(ctx->payload);
87   ident = silc_command_get_ident(ctx->payload);
88       
89   /* Check for pending commands and mark to be exeucted */
90   silc_server_command_pending_check(server, ctx, 
91                                     silc_command_get(ctx->payload), ident);
92
93   /* Execute command reply */
94   command = silc_command_get(ctx->payload);
95   for (cmd = silc_command_reply_list; cmd->cb; cmd++)
96     if (cmd->cmd == command)
97       break;
98
99   if (cmd == NULL) {
100     silc_free(ctx);
101     return;
102   }
103
104   cmd->cb(ctx);
105 }
106
107 /* Free command reply context and its internals. */
108
109 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
110 {
111   if (cmd) {
112     silc_command_free_payload(cmd->payload);
113     silc_free(cmd);
114   }
115 }
116
117 /* Caches the received WHOIS information. If we are normal server currently
118    we cache global information only for short period of time.  If we are
119    router we want to cache them a bit longer since we can receive information
120    if any of the information becomes invalid. Normal server cannot receive
121    that information. Returns FALSE if something was wrong with the reply. */
122
123 static char
124 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
125 {
126   int len, id_len;
127   unsigned char *id_data;
128   char *nickname, *username, *realname;
129   SilcClientID *client_id;
130
131   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
132   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
133   username = silc_argument_get_arg_type(cmd->args, 4, &len);
134   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
135   if (!id_data || !nickname || !username || !realname) 
136     return FALSE;
137
138   client_id = silc_id_payload_parse_id(id_data, id_len);
139
140
141   return TRUE;
142 }
143
144 /* Reiceved reply for WHOIS command. We sent the whois request to our
145    primary router, if we are normal server, and thus has now received reply
146    to the command. We will figure out what client originally sent us the
147    command and will send the reply to it.  If we are router we will figure
148    out who server sent us the command and send reply to that one. */
149
150 SILC_SERVER_CMD_REPLY_FUNC(whois)
151 {
152   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
153   SilcServer server = cmd->server;
154   SilcCommandStatus status;
155
156   SILC_LOG_DEBUG(("Start"));
157
158   COMMAND_CHECK_STATUS_LIST;
159
160   /* Process one identify reply */
161   if (status == SILC_STATUS_OK) {
162
163   }
164
165   if (status == SILC_STATUS_LIST_START) {
166
167   }
168
169   if (status == SILC_STATUS_LIST_ITEM) {
170
171   }
172
173   if (status == SILC_STATUS_LIST_END) {
174
175   }
176
177   /* Execute any pending commands */
178   SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
179
180  out:
181   silc_server_command_reply_free(cmd);
182 }
183
184 /* Received reply for forwarded IDENTIFY command. We have received the
185    requested identify information now and we will cache it. After this we
186    will call the pending command so that the requestee gets the information
187    after all. */
188
189 SILC_SERVER_CMD_REPLY_FUNC(identify)
190 {
191   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
192   SilcServer server = cmd->server;
193   SilcCommandStatus status;
194
195   SILC_LOG_DEBUG(("Start"));
196
197   COMMAND_CHECK_STATUS_LIST;
198
199   /* Process one identify reply */
200   if (status == SILC_STATUS_OK) {
201     SilcClientID *client_id;
202     unsigned int len;
203     unsigned char *id_data;
204     char *nickname, *username;
205
206     id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
207     nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
208     if (!id_data || !nickname)
209       goto out;
210
211     username = silc_argument_get_arg_type(cmd->args, 4, NULL);
212     client_id = silc_id_payload_parse_id(id_data, len);
213
214     /* Add the client always to our global list. If normal or router server
215        ever gets here it means they don't have this client's information
216        in their cache. */
217     silc_idlist_add_client(server->global_list, strdup(nickname),
218                            username, NULL, client_id, NULL, NULL);
219   }
220
221   if (status == SILC_STATUS_LIST_START) {
222
223   }
224
225   if (status == SILC_STATUS_LIST_ITEM) {
226
227   }
228
229   if (status == SILC_STATUS_LIST_END) {
230
231   }
232
233   /* Execute any pending commands */
234   SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
235
236  out:
237   silc_server_command_reply_free(cmd);
238 }
239
240 /* Received reply for forwarded JOIN command. Router has created or joined
241    the client to the channel. We save some channel information locally
242    for future use. */
243
244 SILC_SERVER_CMD_REPLY_FUNC(join)
245 {
246   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
247   SilcServer server = cmd->server;
248   SilcCommandStatus status;
249   SilcChannelID *id;
250   SilcChannelEntry entry;
251   unsigned int len;
252   unsigned char *id_string;
253   char *channel_name, *tmp;
254
255   SILC_LOG_DEBUG(("Start"));
256
257   COMMAND_CHECK_STATUS;
258
259   /* Get channel name */
260   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
261   if (!tmp)
262     goto out;
263
264   /* Get channel ID */
265   id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
266   if (!id_string)
267     goto out;
268
269   channel_name = strdup(tmp);
270   id = silc_id_payload_parse_id(id_string, len);
271
272   /* XXX We should check that we have sent JOIN command to the router
273      in the first place. Also should check that we don't have the channel
274      already in the cache. These checks must be made because of possible
275      buggy routers. */
276
277   SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
278                   silc_id_render(id, SILC_ID_CHANNEL)));
279
280   /* Add the channel to our local list. */
281   entry = silc_idlist_add_channel(server->local_list, channel_name, 
282                                   SILC_CHANNEL_MODE_NONE, id, 
283                                   server->router, NULL);
284   if (!entry) {
285     silc_free(channel_name);
286     silc_free(id);
287     goto out;
288   }
289
290   //entry->global_users = TRUE;
291
292   /* Execute any pending commands */
293   SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
294
295  out:
296   silc_server_command_reply_free(cmd);
297 }