Merged from silc_1_0_branch.
[silc.git] / lib / silccore / silccommand.c
index 3be0583e3a04006ffbf3573184aaea3804abc9c0..a16dfc6fce792b6e0c8edfe1ac0d17265120b219 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silccommand.c
+  silccommand.c 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -76,13 +75,15 @@ SilcCommandPayload silc_command_payload_parse(const unsigned char *payload,
   }
 
   if (newp->cmd == 0) {
+    SILC_LOG_ERROR(("Incorrect command type in command payload"));
     silc_free(newp);
     return NULL;
   }
 
   silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
   if (args_num) {
-    newp->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num);
+    newp->args = silc_argument_payload_parse(buffer.data, buffer.len, 
+                                            args_num);
     if (!newp->args) {
       silc_free(newp);
       return NULL;
@@ -110,6 +111,8 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd,
 
   if (argc) {
     args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
+    if (!args)
+      return NULL;
     len = args->len;
   }
 
@@ -153,7 +156,8 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
 
   if (payload->args) {
     args = silc_argument_payload_encode_payload(payload->args);
-    len = args->len;
+    if (args)
+      len = args->len;
     argc = silc_argument_get_arg_num(payload->args);
   }
 
@@ -270,7 +274,8 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
 
 SilcBuffer 
 silc_command_reply_payload_encode_va(SilcCommand cmd, 
-                                    SilcCommandStatus status,
+                                    SilcStatus status,
+                                    SilcStatus error,
                                     SilcUInt16 ident,
                                     SilcUInt32 argc, ...)
 {
@@ -278,7 +283,8 @@ silc_command_reply_payload_encode_va(SilcCommand cmd,
   SilcBuffer buffer;
 
   va_start(ap, argc);
-  buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap);
+  buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
+                                                ident, argc, ap);
   va_end(ap);
 
   return buffer;
@@ -286,7 +292,8 @@ silc_command_reply_payload_encode_va(SilcCommand cmd,
 
 SilcBuffer 
 silc_command_reply_payload_encode_vap(SilcCommand cmd, 
-                                     SilcCommandStatus status,
+                                     SilcStatus status,
+                                     SilcStatus error,
                                      SilcUInt16 ident, SilcUInt32 argc, 
                                      va_list ap)
 {
@@ -315,7 +322,8 @@ silc_command_reply_payload_encode_vap(SilcCommand cmd,
     return NULL;
   }
 
-  SILC_PUT16_MSB(status, status_data);
+  status_data[0] = status;
+  status_data[1] = error;
   argv[0] = silc_memdup(status_data, sizeof(status_data));
   if (!argv[0]) {
     silc_free(argv_types);
@@ -388,19 +396,45 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
 
 /* Return command status */
 
-SilcCommandStatus silc_command_get_status(SilcCommandPayload payload)
+bool silc_command_get_status(SilcCommandPayload payload, 
+                            SilcStatus *status,
+                            SilcStatus *error)
 {
   unsigned char *tmp;
-  SilcCommandStatus status;
+  SilcUInt32 tmp_len;
 
   if (!payload->args)
     return 0;
-  tmp = silc_argument_get_arg_type(payload->args, 1, NULL);
-  if (!tmp)
+  tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
+  if (!tmp || tmp_len != 2)
     return 0;
 
-  SILC_GET16_MSB(status, tmp);
-  return status;
+  /* Check for 1.0 protocol version which didn't have `error' */
+  if (tmp[0] == 0 && tmp[1] != 0) {
+    /* Protocol 1.0 version */
+    SilcStatus s;
+    SILC_GET16_MSB(s, tmp);
+    if (status)
+      *status = s;
+    if (error)
+      *error = 0;
+    if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
+      *error = s;
+    return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
+  }
+
+  /* Take both status and possible error */
+  if (status)
+    *status = (SilcStatus)tmp[0];
+  if (error)
+    *error = (SilcStatus)tmp[1];
+
+  /* If single error occurred have the both `status' and `error' indicate
+     the error value for convenience. */
+  if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
+    *error = tmp[0];
+
+  return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
 }
 
 /* Function to set identifier to already allocated Command Payload. Command