Added remote version control support to server.
[silc.git] / lib / silcutil / silcutil.c
index ad6b45adac5540749f6eae31b30142efe478a4af..82068283708b5a3b64da0bf4ce23d8ebec0f1310 100644 (file)
@@ -382,11 +382,22 @@ char *silc_format(char *fmt, ...)
 /* Renders ID to suitable to print for example to log file. */
 
 static char rid[256];
+#define _PUT_STRING(d, s)                              \
+do {                                                   \
+  int sp = (sizeof(d) - 1) - strlen(d);                        \
+  if (sp < strlen(s)) {                                        \
+    if (sp)                                            \
+      strncat(d, s, (sizeof(d) - 1) - strlen(d));      \
+  } else {                                             \
+    strncat(d, s, strlen(s));                          \
+  }                                                    \
+} while(0)
 
 char *silc_id_render(void *id, SilcUInt16 type)
 {
   char tmp[100];
   unsigned char tmps[2];
+  char *cp;
 
   memset(rid, 0, sizeof(rid));
   switch(type) {
@@ -400,22 +411,24 @@ char *silc_id_render(void *id, SilcUInt16 type)
        ipv6.sin6_family = AF_INET6;
        memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
        if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
-                        tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST))
-         strcat(rid, tmp);
+                        tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+         _PUT_STRING(rid, tmp);
 #endif
       } else {
        struct in_addr ipv4;
        memmove(&ipv4.s_addr, server_id->ip.data, 4);
-       strcat(rid, inet_ntoa(ipv4));
+       cp = inet_ntoa(ipv4);
+       if (cp)
+         _PUT_STRING(rid, cp);
       }
 
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
-      strcat(rid, tmp);
+      snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
+      _PUT_STRING(rid, tmp);
       SILC_PUT16_MSB(server_id->rnd, tmps);
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
-      strcat(rid, tmp);
+      snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+      _PUT_STRING(rid, tmp);
     }
     break;
   case SILC_ID_CLIENT:
@@ -428,23 +441,25 @@ char *silc_id_render(void *id, SilcUInt16 type)
        ipv6.sin6_family = AF_INET6;
        memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
        if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
-                        tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST))
-         strcat(rid, tmp);
+                        tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+         _PUT_STRING(rid, tmp);
 #endif
       } else {
        struct in_addr ipv4;
        memmove(&ipv4.s_addr, client_id->ip.data, 4);
-       strcat(rid, inet_ntoa(ipv4));
+       cp = inet_ntoa(ipv4);
+       if (cp)
+         _PUT_STRING(rid, cp);
       }
 
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
-      strcat(rid, tmp);
+      snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
+      _PUT_STRING(rid, tmp);
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]", 
+      snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]", 
               client_id->hash[0], client_id->hash[1],
               client_id->hash[2], client_id->hash[3]);
-      strcat(rid, tmp);
+      _PUT_STRING(rid, tmp);
     }
     break;
   case SILC_ID_CHANNEL:
@@ -457,22 +472,24 @@ char *silc_id_render(void *id, SilcUInt16 type)
        ipv6.sin6_family = AF_INET6;
        memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
        if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
-                        tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST))
-         strcat(rid, tmp);
+                        tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+         _PUT_STRING(rid, tmp);
 #endif
       } else {
        struct in_addr ipv4;
        memmove(&ipv4.s_addr, channel_id->ip.data, 4);
-       strcat(rid, inet_ntoa(ipv4));
+       cp = inet_ntoa(ipv4);
+       if (cp)
+         _PUT_STRING(rid, cp);
       }
 
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
-      strcat(rid, tmp);
+      snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
+      _PUT_STRING(rid, tmp);
       SILC_PUT16_MSB(channel_id->rnd, tmps);
       memset(tmp, 0, sizeof(tmp));
-      snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
-      strcat(rid, tmp);
+      snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+      _PUT_STRING(rid, tmp);
     }
     break;
   }
@@ -828,3 +845,109 @@ char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
   
   return strdup(fingerprint);
 }
+
+/* Return TRUE if the `data' is ASCII string. */
+
+bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
+{
+  int i;
+
+  for (i = 0; i < data_len; i++) {
+    if (!isascii(data[i]))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Parses SILC protocol style version string. */
+
+bool silc_parse_version_string(const char *version,
+                              SilcUInt32 *protocol_version,
+                              char **protocol_version_string,
+                              SilcUInt32 *software_version, 
+                              char **software_version_string,
+                              char **vendor_version)
+{
+  char *cp, buf[32];
+  int maj = 0, min = 0;
+
+  if (!strstr(version, "SILC-"))
+    return FALSE;
+
+  cp = (char *)version + 5;
+  if (!cp)
+    return FALSE;
+
+  /* Take protocol version */
+
+  maj = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp) {
+    min = atoi(cp + 1);
+    cp++;
+  }
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  if (protocol_version)
+    *protocol_version = atoi(buf);
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+  if (protocol_version_string)
+    *protocol_version_string = strdup(buf);
+
+  /* Take software version */
+
+  maj = 0; 
+  min = 0;
+  cp = strchr(cp, '-');
+  if (!cp)
+    return FALSE;
+
+  maj = atoi(cp + 1);
+  cp = strchr(cp, '.');
+  if (cp)
+    min = atoi(cp + 1);
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  if (software_version)
+    *software_version = atoi(buf);
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+  if (software_version_string)
+    *software_version_string = strdup(buf);
+
+  /* Take vendor string */
+
+  cp++;
+  if (cp) {
+    cp = strchr(cp, '.');
+    if (cp && cp + 1 && vendor_version)
+      *vendor_version = strdup(cp + 1);
+  }
+
+  return TRUE;
+}
+
+/* Converts version string x.x into number representation. */
+
+SilcUInt32 silc_version_to_num(const char *version)
+{
+  int maj = 0, min = 0;
+  char *cp, buf[32];
+
+  if (!version)
+    return 0;
+
+  cp = (char *)version;
+  maj = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp)
+    min = atoi(cp + 1);
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  return (SilcUInt32)atoi(buf);
+}