Added SILC Server library.
[silc.git] / lib / silccore / silcattrs.c
index 2e64777176ea5bd847758c49e6c56a71c9dfe53c..27f25f7373ebea728ba10e1c984ce7d5e9bca532 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcattrs.c 
+  silcattrs.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2005 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
@@ -19,7 +19,7 @@
 /* Implementation of Attribute Payload routines */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcattrs.h"
 
 /******************************************************************************
@@ -46,7 +46,7 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
 {
   SilcBuffer tmpbuf = NULL;
   unsigned char tmp[4], *str = NULL, *ret;
-  int len;
+  SilcUInt32 len;
 
   /* Encode according to attribute type */
   if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
@@ -70,25 +70,30 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
     case SILC_ATTRIBUTE_SERVICE:
       {
        SilcAttributeObjService *service = object;
+       SilcUInt32 len2;
        if (object_size != sizeof(*service))
          return NULL;
        len = strlen(service->address);
-       str = silc_malloc(7 + len);
-       if (!str)
-         return NULL;
-       SILC_PUT32_MSB(service->port, str);
-       SILC_PUT16_MSB(len, str + 4);
-       memcpy(str + 6, service->address, len);
-       str[6 + len] = service->status;
-       object = str;
-       object_size = 7 + len;
+       len2 = strlen(service->signon);
+       tmpbuf = silc_buffer_alloc_size(13 + len + len2);
+       silc_buffer_format(tmpbuf,
+                          SILC_STR_UI_INT(service->port),
+                          SILC_STR_UI_SHORT(len),
+                          SILC_STR_UI_XNSTRING(service->address, len),
+                          SILC_STR_UI_CHAR(service->status),
+                          SILC_STR_UI_SHORT(len2),
+                          SILC_STR_UI_XNSTRING(service->signon, len2),
+                          SILC_STR_UI_INT(service->idle),
+                          SILC_STR_END);
+       object = tmpbuf->data;
+       object_size = silc_buffer_len(tmpbuf);
       }
       break;
 
     case SILC_ATTRIBUTE_STATUS_MOOD:
     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
       {
-       SilcUInt32 mask = (SilcUInt32)object;
+       SilcUInt32 mask = SILC_PTR_TO_32(object);
        if (object_size != sizeof(SilcUInt32))
          return NULL;
        SILC_PUT32_MSB(mask, tmp);
@@ -114,19 +119,21 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
 
     case SILC_ATTRIBUTE_STATUS_MESSAGE:
     case SILC_ATTRIBUTE_EXTENSION:
+    case SILC_ATTRIBUTE_USER_ICON:
       {
-       SilcAttributeObjMime *mime = object;
+       SilcMime mime = object;
        if (object_size != sizeof(*mime))
          return NULL;
-       object = (void *)mime->mime;
-       object_size = mime->mime_len;
+       str = silc_mime_encode(mime, &object_size);
+       if (!str)
+         return NULL;
       }
       break;
 
     case SILC_ATTRIBUTE_GEOLOCATION:
       {
        SilcAttributeObjGeo *geo = object;
-       int len1, len2, len3, len4;
+       SilcUInt32 len1, len2, len3, len4;
        if (object_size != sizeof(*geo))
          return NULL;
        len1 = (geo->longitude ? strlen(geo->longitude) : 0);
@@ -150,14 +157,14 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
                           SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
                           SILC_STR_END);
        object = tmpbuf->data;
-       object_size = tmpbuf->len;
+       object_size = silc_buffer_len(tmpbuf);
       }
       break;
 
     case SILC_ATTRIBUTE_DEVICE_INFO:
       {
        SilcAttributeObjDevice *dev = object;
-       int len1, len2, len3, len4;
+       SilcUInt32 len1, len2, len3, len4;
        if (object_size != sizeof(*dev))
          return NULL;
        len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
@@ -182,7 +189,7 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
                           SILC_STR_UI16_STRING(len4 ? dev->language : ""),
                           SILC_STR_END);
        object = tmpbuf->data;
-       object_size = tmpbuf->len;
+       object_size = silc_buffer_len(tmpbuf);
       }
       break;
 
@@ -202,7 +209,7 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
                           SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
                           SILC_STR_END);
        object = tmpbuf->data;
-       object_size = tmpbuf->len;
+       object_size = silc_buffer_len(tmpbuf);
       }
       break;
 
@@ -245,6 +252,7 @@ SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
                                                  SilcUInt32 object_size)
 {
   SilcAttributePayload attr;
+  SilcUInt32 tmp_len;
 
   attr = silc_calloc(1, sizeof(*attr));
   if (!attr)
@@ -254,8 +262,8 @@ SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
   attr->flags = flags;
   attr->data =
     silc_attribute_payload_encode_int(attribute, flags, object,
-                                     object_size,
-                                     (SilcUInt32 *)&attr->data_len);
+                                     object_size, &tmp_len);
+  attr->data_len = (SilcUInt16)tmp_len;
   if (!attr->data) {
     silc_free(attr);
     return NULL;
@@ -272,39 +280,40 @@ SilcDList silc_attribute_payload_parse(const unsigned char *payload,
   SilcBufferStruct buffer;
   SilcDList list;
   SilcAttributePayload newp;
-  int len, ret;
+  SilcUInt32 len;
+  int ret;
 
   SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
 
   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
   list = silc_dlist_init();
 
-  while (buffer.len) {
+  while (silc_buffer_len(&buffer)) {
     newp = silc_calloc(1, sizeof(*newp));
     if (!newp)
       goto err;
     ret = silc_buffer_unformat(&buffer,
                               SILC_STR_UI_CHAR(&newp->attribute),
                               SILC_STR_UI_CHAR(&newp->flags),
-                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
+                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
                                                           &newp->data_len),
                               SILC_STR_END);
     if (ret == -1)
       goto err;
 
-    if (newp->data_len > buffer.len) {
+    if (newp->data_len > silc_buffer_len(&buffer) - 4) {
       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
       goto err;
     }
 
     len = 4 + newp->data_len;
-    if (buffer.len < len)
+    if (silc_buffer_len(&buffer) < len)
       break;
     silc_buffer_pull(&buffer, len);
 
     silc_dlist_add(list, newp);
   }
-  
+
   return list;
 
  err:
@@ -338,20 +347,20 @@ SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
                                              SilcUInt32 data_len)
 {
   SilcBuffer buffer = attrs;
-  int len;
+  SilcUInt32 len;
 
-  len = 4 + data_len;
+  len = 4 + (SilcUInt16)data_len;
   buffer = silc_buffer_realloc(buffer,
-                              (buffer ? buffer->truelen + len : len));
+                              (buffer ? silc_buffer_truelen(buffer) + len : len));
   if (!buffer)
     return NULL;
-  silc_buffer_pull(buffer, buffer->len);
+  silc_buffer_pull(buffer, silc_buffer_len(buffer));
   silc_buffer_pull_tail(buffer, len);
-  silc_buffer_format(buffer, 
+  silc_buffer_format(buffer,
                     SILC_STR_UI_CHAR(attribute),
                     SILC_STR_UI_CHAR(flags),
                     SILC_STR_UI_SHORT((SilcUInt16)data_len),
-                    SILC_STR_UI_XNSTRING(data, data_len),
+                    SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
                     SILC_STR_END);
   silc_buffer_push(buffer, buffer->data - buffer->head);
 
@@ -401,14 +410,14 @@ const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
                                             SilcUInt32 *data_len)
 {
   if (data_len)
-    *data_len = payload->data_len;
+    *data_len = (SilcUInt32)payload->data_len;
   return (const unsigned char *)payload->data;
 }
 
 /* Construct digital signature verification data */
 
 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
-                                             bool server_verification,
+                                             SilcBool server_verification,
                                              SilcUInt32 *data_len)
 {
   SilcAttributePayload attr;
@@ -437,7 +446,7 @@ unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
       if (!data)
        return NULL;
       silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
-      silc_buffer_format(&buffer, 
+      silc_buffer_format(&buffer,
                         SILC_STR_UI_CHAR(attr->attribute),
                         SILC_STR_UI_CHAR(attr->flags),
                         SILC_STR_UI_SHORT(attr->data_len),
@@ -456,11 +465,11 @@ unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
 
 /* Return parsed attribute object */
 
-bool silc_attribute_get_object(SilcAttributePayload payload,
+SilcBool silc_attribute_get_object(SilcAttributePayload payload,
                               void *object, SilcUInt32 object_size)
 {
   SilcUInt16 len;
-  bool ret = FALSE;
+  SilcBool ret = FALSE;
 
   if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
     return FALSE;
@@ -480,18 +489,32 @@ bool silc_attribute_get_object(SilcAttributePayload payload,
   case SILC_ATTRIBUTE_SERVICE:
     {
       SilcAttributeObjService *service = object;
+      SilcBufferStruct buf;
+      SilcUInt16 addr_len, signon_len;
+      char *addr, *signon;
+      int res;
       if (object_size != sizeof(*service))
        break;
-      if (payload->data_len < 7)
+      if (payload->data_len < 13)
        break;
-      SILC_GET32_MSB(service->port, payload->data);
-      SILC_GET16_MSB(len, payload->data + 4);
-      if (payload->data_len < 7 + len)
+      silc_buffer_set(&buf, payload->data, payload->data_len);
+      res = silc_buffer_unformat(&buf,
+                                SILC_STR_UI_INT(&service->port),
+                                SILC_STR_UI16_NSTRING(&addr, &addr_len),
+                                SILC_STR_UI_CHAR(&service->status),
+                                SILC_STR_UI16_NSTRING(&signon, &signon_len),
+                                SILC_STR_UI_INT(&service->idle),
+                                SILC_STR_END);
+      if (res == -1)
        break;
-      memcpy(service->address, payload->data + 6,
-            (len < sizeof(service->address) - 1 ? len :
+      memset(service->address, 0, sizeof(service->address));
+      memset(service->signon, 0, sizeof(service->signon));
+      memcpy(service->address, addr,
+            (addr_len < sizeof(service->address) - 1 ? addr_len :
              sizeof(service->address) - 1));
-      service->status = payload->data[6 + len] ? TRUE : FALSE;
+      memcpy(service->signon, signon,
+            (signon_len < sizeof(service->signon) - 1 ? signon_len :
+             sizeof(service->signon) - 1));
       ret = TRUE;
     }
     break;
@@ -528,12 +551,13 @@ bool silc_attribute_get_object(SilcAttributePayload payload,
 
   case SILC_ATTRIBUTE_STATUS_MESSAGE:
   case SILC_ATTRIBUTE_EXTENSION:
+  case SILC_ATTRIBUTE_USER_ICON:
     {
-      SilcAttributeObjMime *mime = object;
+      SilcMime mime = object;
       if (object_size != sizeof(*mime))
        break;
-      mime->mime = (const unsigned char *)payload->data;
-      mime->mime_len = payload->data_len;
+      if (!silc_mime_decode(mime, payload->data, payload->data_len))
+       break;
       ret = TRUE;
     }
     break;
@@ -598,7 +622,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload,
        silc_buffer_unformat(&buffer,
                             SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
                             SILC_STR_END);
-      if (res == -1)
+      if (res == -1 || len > silc_buffer_len(&buffer) - 2)
        break;
       pk->data = silc_memdup(payload->data + 2 + len,
                             payload->data_len - 2 - len);