Added SILC Thread Queue API
[crypto.git] / lib / silcserver / server_st_command.c
1 /*
2
3   server_st_command.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21 #include "silcserver.h"
22 #include "server_internal.h"
23
24 /************************** Types and definitions ***************************/
25
26 #define SILC_SERVER_COMMAND_CHECK(min, max)                             \
27 do {                                                                    \
28   SilcUInt32 _argc;                                                     \
29                                                                         \
30   SILC_LOG_DEBUG(("Start"));                                            \
31                                                                         \
32   _argc = silc_argument_get_arg_num(args);                              \
33   if (_argc < min) {                                                    \
34     SILC_LOG_DEBUG(("Not enough parameters in command"));               \
35     silc_server_command_status_reply(cmd,                               \
36                                      silc_command_get(cmd->payload),    \
37                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
38                                      0);                                \
39     silc_server_command_free(cmd);                                      \
40     return SILC_FSM_FINISH;                                             \
41   }                                                                     \
42   if (_argc > max) {                                                    \
43     SILC_LOG_DEBUG(("Too many parameters in command"));                 \
44     silc_server_command_status_reply(cmd,                               \
45                                      silc_command_get(cmd->payload),    \
46                                      SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
47                                      0);                                \
48     silc_server_command_free(cmd);                                      \
49     return SILC_FSM_FINISH;                                             \
50   }                                                                     \
51 } while(0)
52
53
54 /************************ Static utility functions **************************/
55
56 /* Sends simple status message as command reply packet */
57
58 static void
59 silc_server_command_status_reply(SilcServerCommand cmd,
60                                       SilcCommand command,
61                                       SilcStatus status,
62                                       SilcStatus error)
63 {
64   SilcBuffer buffer;
65
66   /* Statistics */
67   cmd->thread->server->stat.commands_sent++;
68
69   SILC_LOG_DEBUG(("Sending command status %d", status));
70   buffer =
71     silc_command_reply_payload_encode_va(command, status, error,
72                                          silc_command_get_ident(cmd->payload),
73                                          0);
74   silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
75                    buffer->data, silc_buffer_len(buffer));
76   silc_buffer_free(buffer);
77 }
78
79 /* Sends command status reply with one extra argument. The argument
80    type must be sent as argument. */
81
82 static void
83 silc_server_command_status_data(SilcServerCommand cmd,
84                                      SilcCommand command,
85                                      SilcStatus status,
86                                      SilcStatus error,
87                                      SilcUInt32 arg_type,
88                                      const unsigned char *arg,
89                                      SilcUInt32 arg_len)
90 {
91   SilcBuffer buffer;
92
93   /* Statistics */
94   cmd->thread->server->stat.commands_sent++;
95
96   SILC_LOG_DEBUG(("Sending command status %d", status));
97
98   buffer =
99     silc_command_reply_payload_encode_va(command, status, 0,
100                                          silc_command_get_ident(cmd->payload),
101                                          1, arg_type, arg, arg_len);
102   silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
103                    buffer->data, silc_buffer_len(buffer));
104   silc_buffer_free(buffer);
105 }
106
107 static void
108 silc_server_command_status_data2(SilcServerCommand cmd,
109                                       SilcCommand command,
110                                       SilcStatus status,
111                                       SilcStatus error,
112                                       SilcUInt32 arg_type1,
113                                       const unsigned char *arg1,
114                                       SilcUInt32 arg_len1,
115                                       SilcUInt32 arg_type2,
116                                       const unsigned char *arg2,
117                                       SilcUInt32 arg_len2)
118 {
119   SilcBuffer buffer;
120
121   /* Statistics */
122   cmd->thread->server->stat.commands_sent++;
123
124   SILC_LOG_DEBUG(("Sending command status %d", status));
125
126   buffer =
127     silc_command_reply_payload_encode_va(command, status, 0,
128                                          silc_command_get_ident(cmd->payload),
129                                          2, arg_type1, arg1, arg_len1,
130                                          arg_type2, arg2, arg_len2);
131   silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
132                    buffer->data, silc_buffer_len(buffer));
133   silc_buffer_free(buffer);
134 }
135
136 void silc_server_command_pending_free(SilcServerThread thread,
137                                       SilcServerPending pending);
138
139
140 /**************************** Utility functions *****************************/
141
142 /* Gets command context from freelist or allocates a new one. */
143
144 SilcServerCommand silc_server_command_alloc(SilcServerThread thread)
145 {
146   SilcServerCommand cmd;
147
148   silc_mutex_lock(thread->server->lock);
149
150   /* Get command context from freelist or allocate new one. */
151   cmd = silc_list_get(thread->server->command_pool);
152   if (!cmd) {
153     silc_mutex_unlock(thread->server->lock);
154
155     cmd = silc_calloc(1, sizeof(*cmd));
156     if (!cmd)
157       return NULL;
158
159     SILC_LOG_DEBUG(("Allocating command context %p", cmd));
160
161     cmd->thread = thread;
162
163     return cmd;
164   }
165
166   SILC_LOG_DEBUG(("Get command context %p", cmd));
167
168   /* Delete from freelist */
169   silc_list_del(thread->server->command_pool, cmd);
170
171   cmd->thread = thread;
172
173   silc_mutex_unlock(thread->server->lock);
174
175   return cmd;
176 }
177
178 /* Puts the command context back to freelist */
179
180 void silc_server_command_free(SilcServerCommand cmd)
181 {
182   SilcServerThread thread = cmd->thread;
183
184   silc_mutex_lock(thread->server->lock);
185
186 #if defined(SILC_DEBUG)
187   /* Check for double free */
188   assert(cmd->packet != NULL);
189 #endif /* SILC_DEBUG */
190
191   if (cmd->packet)
192     silc_packet_free(cmd->packet);
193   cmd->packet = NULL;
194
195   if (cmd->pending)
196     silc_server_command_pending_free(thread, cmd->pending);
197
198   /* Put the packet back to freelist */
199   silc_list_add(thread->server->command_pool, cmd);
200
201   silc_mutex_unlock(thread->server->lock);
202 }
203
204 /* Returns pending context used to wait for a command reply. */
205
206 SilcServerPending silc_server_command_pending(SilcServerThread thread,
207                                               SilcUInt16 cmd_ident)
208 {
209   SilcServerPending pending;
210
211   silc_mutex_lock(thread->server->lock);
212
213   /* Check if pending already */
214   if (silc_hash_table_find(thread->server->pending_commands,
215                            SILC_32_TO_PTR(cmd_ident), NULL,
216                            (void **)&pending)) {
217     pending->refcnt++;
218     silc_mutex_unlock(thread->server->lock);
219     return pending;
220   }
221
222   pending = silc_calloc(1, sizeof(*pending));
223   if (!pending) {
224     silc_mutex_unlock(thread->server->lock);
225     return NULL;
226   }
227
228   silc_fsm_event_init(&pending->wait_reply, &thread->fsm, 0);
229   pending->refcnt = 1;
230   pending->cmd_ident = cmd_ident;
231
232   /* Add to pending commands hash table */
233   if (!silc_hash_table_add(thread->server->pending_commands,
234                            SILC_32_TO_PTR(cmd_ident), pending)) {
235     silc_mutex_unlock(thread->server->lock);
236     silc_free(pending);
237     return NULL;
238   }
239
240   silc_mutex_unlock(thread->server->lock);
241
242   return pending;
243 }
244
245 /* Free's the pending command context */
246
247 void silc_server_command_pending_free(SilcServerThread thread,
248                                       SilcServerPending pending)
249 {
250   silc_mutex_lock(thread->server->lock);
251
252   pending->refcnt--;
253   if (pending->refcnt > 0) {
254     silc_mutex_unlock(thread->server->lock);
255     return;
256   }
257
258   /* If command reply context set, free it also */
259   if (pending->reply) {
260     pending->reply->pending = NULL;
261     silc_server_command_free(pending->reply);
262   }
263
264   /* Remove from pending commands */
265   silc_hash_table_del_by_context(thread->server->pending_commands,
266                                  SILC_32_TO_PTR(pending->cmd_ident), pending);
267   silc_free(pending);
268
269   silc_mutex_unlock(thread->server->lock);
270 }
271
272 /* Returns pending command context for command identifier */
273
274 SilcServerPending silc_server_command_pending_get(SilcServerThread thread,
275                                                   SilcUInt16 cmd_ident)
276 {
277   SilcServerPending pending = NULL;
278
279   silc_mutex_lock(thread->server->lock);
280   silc_hash_table_find(thread->server->pending_commands,
281                        SILC_32_TO_PTR(cmd_ident), NULL, (void **)&pending);
282   silc_mutex_unlock(thread->server->lock);
283
284   return pending;
285 }
286
287 /* Signals pending command waiters.  Used by command reply routines. */
288
289 void silc_server_command_pending_signal(SilcServerCommand cmd)
290 {
291   SilcServerThread thread = cmd->thread;
292   SilcServerPending pending = cmd->pending;
293
294   if (!pending)
295     return;
296
297   silc_mutex_lock(thread->server->lock);
298
299   /* Signal */
300   pending->reply = cmd;
301   SILC_FSM_EVENT_SIGNAL(&pending->wait_reply);
302
303   /* Remove from pending */
304   silc_hash_table_del_by_context(thread->server->pending_commands,
305                                  SILC_32_TO_PTR(pending->cmd_ident), pending);
306
307   silc_mutex_unlock(thread->server->lock);
308 }
309
310
311 /**************************** Command received ******************************/
312
313 /* Received a COMMAND packet.  We parse the packet and process the
314    requested command. */
315
316 SILC_FSM_STATE(silc_server_st_packet_command)
317 {
318   SilcServerThread thread = fsm_context;
319   SilcPacket packet = state_context;
320   SilcEntryData data = silc_packet_get_context(packet->stream);
321   SilcServerCommand cmd;
322   SilcUInt32 timeout = 0;
323
324   /* Allocate command context. */
325   cmd = silc_server_command_alloc(thread);
326   if (!cmd) {
327     silc_packet_free(packet);
328     return SILC_FSM_FINISH;
329   }
330
331   cmd->packet = packet;
332
333   /* Parse the command payload in the packet */
334   cmd->payload = silc_command_payload_parse(packet->buffer.data,
335                                             silc_buffer_len(&packet->buffer));
336   if (!cmd->payload) {
337     SILC_LOG_ERROR(("Bad command payload"));
338     silc_server_command_free(cmd);
339     return SILC_FSM_FINISH;
340   }
341
342   /* If client executes commands more frequently than once in 2 seconds,
343      apply 0 - 2 seconds of timeout to prevent flooding. */
344   if (data->type == SILC_CONN_CLIENT) {
345     SilcClientEntry client = (SilcClientEntry)data;
346
347     if (client->last_command && (time(NULL) - client->last_command) < 2) {
348       client->fast_command++;
349       if (client->fast_command > 5)
350         timeout = (client->fast_command < 3 ? 0 :
351                    2 - (time(NULL) - client->last_command));
352     } else {
353       if (client->fast_command - 2 <= 0)
354         client->fast_command = 0;
355       else
356         client->fast_command -= 2;
357     }
358
359     client->last_command = time(NULL) + timeout;
360   }
361
362   silc_fsm_set_state_context(fsm, cmd);
363
364   SILC_LOG_DEBUG(("Processing %s command (%d timeout)",
365                   silc_get_command_name(silc_command_get(cmd->payload)),
366                   timeout));
367
368   /* Process command */
369   switch (silc_command_get(cmd->payload)) {
370
371   case SILC_COMMAND_WHOIS:
372     /** Command WHOIS */
373     silc_fsm_next_later(fsm, silc_server_st_command_whois, timeout, 0);
374     break;
375
376   case SILC_COMMAND_WHOWAS:
377     /** Command WHOWAS */
378     silc_fsm_next_later(fsm, silc_server_st_command_whowas, timeout, 0);
379     break;
380
381   case SILC_COMMAND_IDENTIFY:
382     /** Command IDENTIFY */
383     silc_fsm_next_later(fsm, silc_server_st_command_identify, timeout, 0);
384     break;
385
386   case SILC_COMMAND_NICK:
387     /** Command NICK */
388     silc_fsm_next_later(fsm, silc_server_st_command_nick, timeout, 0);
389     break;
390
391   case SILC_COMMAND_LIST:
392     /** Command LIST */
393     silc_fsm_next_later(fsm, silc_server_st_command_list, timeout, 0);
394     break;
395
396   case SILC_COMMAND_TOPIC:
397     /** Command TOPIC */
398     silc_fsm_next_later(fsm, silc_server_st_command_topic, timeout, 0);
399     break;
400
401   case SILC_COMMAND_INVITE:
402     /** Command INVITE */
403     silc_fsm_next_later(fsm, silc_server_st_command_invite, timeout, 0);
404     break;
405
406   case SILC_COMMAND_QUIT:
407     /** Command QUIT */
408     silc_fsm_next_later(fsm, silc_server_st_command_quit, timeout, 0);
409     break;
410
411   case SILC_COMMAND_KILL:
412     /** Command KILL */
413     silc_fsm_next_later(fsm, silc_server_st_command_kill, timeout, 0);
414     break;
415
416   case SILC_COMMAND_INFO:
417     /** Command INFO */
418     silc_fsm_next_later(fsm, silc_server_st_command_info, timeout, 0);
419     break;
420
421   case SILC_COMMAND_STATS:
422     /** Command STATS */
423     silc_fsm_next_later(fsm, silc_server_st_command_stats, timeout, 0);
424     break;
425
426   case SILC_COMMAND_PING:
427     /** Command INFO */
428     silc_fsm_next_later(fsm, silc_server_st_command_ping, timeout, 0);
429     break;
430
431   case SILC_COMMAND_OPER:
432     /** Command OPER */
433     silc_fsm_next_later(fsm, silc_server_st_command_oper, timeout, 0);
434     break;
435
436   case SILC_COMMAND_JOIN:
437     /** Command JOIN */
438     silc_fsm_next_later(fsm, silc_server_st_command_join, timeout, 0);
439     break;
440
441   case SILC_COMMAND_MOTD:
442     /** Command MOTD */
443     silc_fsm_next_later(fsm, silc_server_st_command_motd, timeout, 0);
444     break;
445
446   case SILC_COMMAND_UMODE:
447     /** Command UMODE */
448     silc_fsm_next_later(fsm, silc_server_st_command_umode, timeout, 0);
449     break;
450
451   case SILC_COMMAND_CMODE:
452     /** Command CMODE */
453     silc_fsm_next_later(fsm, silc_server_st_command_cmode, timeout, 0);
454     break;
455
456   case SILC_COMMAND_CUMODE:
457     /** Command CUMODE */
458     silc_fsm_next_later(fsm, silc_server_st_command_cumode, timeout, 0);
459     break;
460
461   case SILC_COMMAND_KICK:
462     /** Command KICK */
463     silc_fsm_next_later(fsm, silc_server_st_command_kick, timeout, 0);
464     break;
465
466   case SILC_COMMAND_BAN:
467     /** Command BAN */
468     silc_fsm_next_later(fsm, silc_server_st_command_ban, timeout, 0);
469     break;
470
471   case SILC_COMMAND_DETACH:
472     /** Command DETACH */
473     silc_fsm_next_later(fsm, silc_server_st_command_detach, timeout, 0);
474     break;
475
476   case SILC_COMMAND_WATCH:
477     /** Command WATCH */
478     silc_fsm_next_later(fsm, silc_server_st_command_watch, timeout, 0);
479     break;
480
481   case SILC_COMMAND_SILCOPER:
482     /** Command SILCOPER */
483     silc_fsm_next_later(fsm, silc_server_st_command_silcoper, timeout, 0);
484     break;
485
486   case SILC_COMMAND_LEAVE:
487     /** Command LEAVE */
488     silc_fsm_next_later(fsm, silc_server_st_command_leave, timeout, 0);
489     break;
490
491   case SILC_COMMAND_USERS:
492     /** Command USERS */
493     silc_fsm_next_later(fsm, silc_server_st_command_users, timeout, 0);
494     break;
495
496   case SILC_COMMAND_GETKEY:
497     /** Command GETKEY */
498     silc_fsm_next_later(fsm, silc_server_st_command_getkey, timeout, 0);
499     break;
500
501   case SILC_COMMAND_SERVICE:
502     /** Command SERVICE */
503     silc_fsm_next_later(fsm, silc_server_st_command_service, timeout, 0);
504     break;
505
506   default:
507     SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
508     silc_server_command_free(cmd);
509     return SILC_FSM_FINISH;
510     break;
511   }
512
513   /* Statistics */
514   thread->server->stat.commands_received++;
515
516   return timeout ? SILC_FSM_WAIT : return SILC_FSM_CONTINUE;
517 }
518
519 /********************************* WHOIS ************************************/
520
521 SILC_FSM_STATE(silc_server_st_command_whois)
522 {
523   SilcServerCommand cmd = state_context;
524   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
525
526   SILC_SERVER_COMMAND_CHECK(1, 256);
527
528   /** WHOIS query */
529   silc_fsm_next(fsm, silc_server_st_query_whois);
530
531   return SILC_FSM_CONTINUE;
532 }
533
534
535 /********************************* WHOWAS ***********************************/
536
537 SILC_FSM_STATE(silc_server_st_command_whowas)
538 {
539   SilcServerCommand cmd = state_context;
540   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
541
542   SILC_SERVER_COMMAND_CHECK(1, 2);
543
544   /** WHOWAS query */
545   silc_fsm_next(fsm, silc_server_st_query_whowas);
546
547   return SILC_FSM_CONTINUE;
548 }
549
550
551 /******************************** IDENTIFY **********************************/
552
553 SILC_FSM_STATE(silc_server_st_command_identify)
554 {
555   SilcServerCommand cmd = state_context;
556   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
557
558   SILC_SERVER_COMMAND_CHECK(1, 256);
559
560   /** IDENTIFY query */
561   silc_fsm_next(fsm, silc_server_st_query_identify);
562
563   return SILC_FSM_CONTINUE;
564 }
565
566
567 /********************************** NICK ************************************/
568
569 SILC_FSM_STATE(silc_server_st_command_nick)
570 {
571   SilcServerThread thread = fsm_context;
572   SilcServerCommand cmd = state_context;
573   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
574   SilcClientEntry client = silc_packet_get_context(cmd->packet->stream);
575   SilcBuffer nidp, oidp = NULL;
576   SilcClientID new_id;
577   SilcUInt32 nick_len;
578   unsigned char *nick, *nickc;
579   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
580
581   SILC_SERVER_COMMAND_CHECK(1, 1);
582
583   /* This command can come only from client */
584   if (!SILC_IS_CLIENT(client)) {
585     silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
586                                      SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
587     goto out;
588   }
589
590   /* Get nickname */
591   nick = silc_argument_get_arg_type(args, 1, &nick_len);
592   if (!nick) {
593     silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
594                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
595     goto out;
596   }
597
598   /* Truncate over long nicks */
599   if (nick_len > 128) {
600     nick_len = 128;
601     nick[nick_len - 1] = '\0';
602   }
603
604   /* Check for same nickname */
605   if (strlen(client->nickname) == nick_len &&
606       !memcmp(client->nickname, nick, nick_len)) {
607     nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
608     goto send_reply;
609   }
610
611   /* Check for valid nickname string. */
612   nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
613   if (!nickc) {
614     silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
615                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
616     goto out;
617   }
618
619   /* Create new Client ID */
620   if (!silc_server_create_client_id(thread->server, nickc, &new_id)) {
621     silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
622                                      SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
623     goto out;
624   }
625   silc_free(nickc);
626
627   oidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
628
629   /* Replace the old nickname and ID with new ones.  This checks for
630      validity of the nickname too. */
631   if (!silc_server_replace_client_id(thread->server, &client->id, &new_id,
632                                      nick)) {
633     silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
634                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
635     goto out;
636   }
637
638   nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
639
640 #if 0
641   /* Send notify about nickname and ID change to network. */
642   silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
643                                       SILC_BROADCAST(server), client->id,
644                                       &new_id, nick);
645
646   /* Send NICK_CHANGE notify to the client's channels */
647   silc_server_send_notify_on_channels(server, NULL, client,
648                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
649                                       oidp->data, silc_buffer_len(oidp),
650                                       nidp->data, silc_buffer_len(nidp),
651                                       client->nickname,
652                                       strlen(client->nickname));
653 #endif
654
655  send_reply:
656   /* Send the new Client ID as reply command back to client */
657   silc_server_send_command_reply(thread->server, cmd->packet->stream,
658                                  SILC_COMMAND_NICK,
659                                  SILC_STATUS_OK, 0, ident, 2,
660                                  2, nidp->data, silc_buffer_len(nidp),
661                                  3, nick, nick_len);
662   silc_buffer_free(nidp);
663   silc_buffer_free(oidp);
664
665  out:
666   silc_server_command_free(cmd);
667   return SILC_FSM_FINISH;
668 }
669
670
671 /********************************** LIST ************************************/
672
673 SILC_FSM_STATE(silc_server_st_command_list)
674 {
675   SilcServerThread thread = fsm_context;
676   SilcServerCommand cmd = state_context;
677   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
678
679   return SILC_FSM_FINISH;
680 }
681
682
683 /********************************** TOPIC ***********************************/
684
685 SILC_FSM_STATE(silc_server_st_command_topic)
686 {
687   SilcServerThread thread = fsm_context;
688   SilcServerCommand cmd = state_context;
689   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
690
691   return SILC_FSM_FINISH;
692 }
693
694
695 /********************************* INVITE ***********************************/
696
697 SILC_FSM_STATE(silc_server_st_command_invite)
698 {
699   SilcServerThread thread = fsm_context;
700   SilcServerCommand cmd = state_context;
701   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
702
703   return SILC_FSM_FINISH;
704 }
705
706
707 /********************************** QUIT ************************************/
708
709 SILC_FSM_STATE(silc_server_st_command_quit)
710 {
711   SilcServerThread thread = fsm_context;
712   SilcServerCommand cmd = state_context;
713   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
714
715   return SILC_FSM_FINISH;
716 }
717
718
719 /********************************** KILL ************************************/
720
721 SILC_FSM_STATE(silc_server_st_command_kill)
722 {
723   SilcServerThread thread = fsm_context;
724   SilcServerCommand cmd = state_context;
725   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
726
727   return SILC_FSM_FINISH;
728 }
729
730
731 /********************************** INFO ************************************/
732
733 SILC_FSM_STATE(silc_server_st_command_info)
734 {
735   return SILC_FSM_FINISH;
736 }
737
738
739 /********************************** STATS ***********************************/
740
741 SILC_FSM_STATE(silc_server_st_command_stats)
742 {
743   SilcServerThread thread = fsm_context;
744   SilcServerCommand cmd = state_context;
745   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
746
747   return SILC_FSM_FINISH;
748 }
749
750
751 /********************************** PING ************************************/
752
753 SILC_FSM_STATE(silc_server_st_command_ping)
754 {
755   SilcServerThread thread = fsm_context;
756   SilcServerCommand cmd = state_context;
757   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
758   SilcUInt32 tmp_len;
759   unsigned char *tmp;
760   SilcID id;
761
762   SILC_SERVER_COMMAND_CHECK(1, 1);
763
764   /* Get Server ID */
765   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
766   if (!tmp) {
767     silc_server_command_status_reply(cmd, silc_command_get(cmd->payload),
768                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
769     goto out;
770   }
771   if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
772     silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
773                                     SILC_STATUS_ERR_BAD_SERVER_ID, 0,
774                                     2, tmp, tmp_len);
775     goto out;
776   }
777
778   /* Must be our ID */
779   if (!SILC_ID_SERVER_COMPARE(&id.u.server_id, &thread->server->id)) {
780     silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
781                                     SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
782                                     2, tmp, tmp_len);
783     goto out;
784   }
785
786   /* Send our reply */
787   silc_server_command_status_reply(cmd, silc_command_get(cmd->payload),
788                                    SILC_STATUS_OK, 0);
789
790  out:
791   silc_server_command_free(cmd);
792   return SILC_FSM_FINISH;
793 }
794
795
796 /*********************************** OPER ***********************************/
797
798 SILC_FSM_STATE(silc_server_st_command_oper)
799 {
800   SilcServerThread thread = fsm_context;
801   SilcServerCommand cmd = state_context;
802   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
803
804   return SILC_FSM_FINISH;
805 }
806
807
808 /*********************************** JOIN ***********************************/
809
810 SILC_FSM_STATE(silc_server_st_command_join)
811 {
812   SilcServerThread thread = fsm_context;
813   SilcServerCommand cmd = state_context;
814   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
815
816   return SILC_FSM_FINISH;
817 }
818
819
820 /*********************************** MOTD ***********************************/
821
822 SILC_FSM_STATE(silc_server_st_command_motd)
823 {
824   SilcServerThread thread = fsm_context;
825   SilcServerCommand cmd = state_context;
826   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
827
828   return SILC_FSM_FINISH;
829 }
830
831
832 /*********************************** UMODE **********************************/
833
834 SILC_FSM_STATE(silc_server_st_command_umode)
835 {
836   SilcServerThread thread = fsm_context;
837   SilcServerCommand cmd = state_context;
838   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
839
840   return SILC_FSM_FINISH;
841 }
842
843
844 /*********************************** CMODE **********************************/
845
846 SILC_FSM_STATE(silc_server_st_command_cmode)
847 {
848   SilcServerThread thread = fsm_context;
849   SilcServerCommand cmd = state_context;
850   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
851
852   return SILC_FSM_FINISH;
853 }
854
855
856 /********************************** CUMODE **********************************/
857
858 SILC_FSM_STATE(silc_server_st_command_cumode)
859 {
860   SilcServerThread thread = fsm_context;
861   SilcServerCommand cmd = state_context;
862   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
863
864   return SILC_FSM_FINISH;
865 }
866
867
868 /*********************************** KICK ***********************************/
869
870 SILC_FSM_STATE(silc_server_st_command_kick)
871 {
872   SilcServerThread thread = fsm_context;
873   SilcServerCommand cmd = state_context;
874   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
875
876   return SILC_FSM_FINISH;
877 }
878
879
880 /*********************************** BAN ************************************/
881
882 SILC_FSM_STATE(silc_server_st_command_ban)
883 {
884   SilcServerThread thread = fsm_context;
885   SilcServerCommand cmd = state_context;
886   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
887
888   return SILC_FSM_FINISH;
889 }
890
891
892 /********************************** DETACH **********************************/
893
894 SILC_FSM_STATE(silc_server_st_command_detach)
895 {
896   SilcServerThread thread = fsm_context;
897   SilcServerCommand cmd = state_context;
898   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
899
900   return SILC_FSM_FINISH;
901 }
902
903
904 /********************************** WATCH ***********************************/
905
906 SILC_FSM_STATE(silc_server_st_command_watch)
907 {
908   SilcServerThread thread = fsm_context;
909   SilcServerCommand cmd = state_context;
910   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
911
912   return SILC_FSM_FINISH;
913 }
914
915
916 /********************************* SILCOPER *********************************/
917
918 SILC_FSM_STATE(silc_server_st_command_silcoper)
919 {
920   SilcServerThread thread = fsm_context;
921   SilcServerCommand cmd = state_context;
922   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
923
924   return SILC_FSM_FINISH;
925 }
926
927
928 /********************************** LEAVE ***********************************/
929
930 SILC_FSM_STATE(silc_server_st_command_leave)
931 {
932   SilcServerThread thread = fsm_context;
933   SilcServerCommand cmd = state_context;
934   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
935
936   return SILC_FSM_FINISH;
937 }
938
939
940 /********************************** USERS ***********************************/
941
942 SILC_FSM_STATE(silc_server_st_command_users)
943 {
944   SilcServerThread thread = fsm_context;
945   SilcServerCommand cmd = state_context;
946   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
947
948   return SILC_FSM_FINISH;
949 }
950
951
952 /********************************** GETKEY **********************************/
953
954 SILC_FSM_STATE(silc_server_st_command_getkey)
955 {
956   SilcServerThread thread = fsm_context;
957   SilcServerCommand cmd = state_context;
958   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
959
960   return SILC_FSM_FINISH;
961 }
962
963
964 /********************************** SERVICE *********************************/
965
966 SILC_FSM_STATE(silc_server_st_command_service)
967 {
968   SilcServerThread thread = fsm_context;
969   SilcServerCommand cmd = state_context;
970   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
971
972   return SILC_FSM_FINISH;
973 }