+/* Parses command line. At most `max_args' is taken. Rest of the line
+ will be allocated as the last argument if there are more than `max_args'
+ arguments in the line. Note that the command name is counted as one
+ argument and is saved. */
+
+void silc_parse_command_line(unsigned char *buffer,
+ unsigned char ***parsed,
+ SilcUInt32 **parsed_lens,
+ SilcUInt32 **parsed_types,
+ SilcUInt32 *parsed_num,
+ SilcUInt32 max_args)
+{
+ int i, len = 0;
+ int argc = 0;
+ const char *cp = buffer;
+ char *tmp;
+
+ *parsed = silc_calloc(1, sizeof(**parsed));
+ *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
+
+ /* Get the command first */
+ len = strcspn(cp, " ");
+ tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
+ if (!tmp)
+ return;
+ silc_to_upper(cp, tmp, strlen(cp));
+ (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
+ memcpy((*parsed)[0], tmp, len);
+ silc_free(tmp);
+ (*parsed_lens)[0] = len;
+ cp += len;
+ while (*cp == ' ')
+ cp++;
+ argc++;
+
+ /* Parse arguments */
+ if (strchr(cp, ' ') || strlen(cp) != 0) {
+ for (i = 1; i < max_args; i++) {
+
+ if (i != max_args - 1)
+ len = strcspn(cp, " ");
+ else
+ len = strlen(cp);
+ while (len && cp[len - 1] == ' ')
+ len--;
+ if (!len)
+ break;
+
+ *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
+ *parsed_lens = silc_realloc(*parsed_lens,
+ sizeof(**parsed_lens) * (argc + 1));
+ (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
+ memcpy((*parsed)[argc], cp, len);
+ (*parsed_lens)[argc] = len;
+ argc++;
+
+ cp += len;
+ if (strlen(cp) == 0)
+ break;
+ else
+ while (*cp == ' ')
+ cp++;
+ }
+ }
+
+ /* Save argument types. Protocol defines all argument types but
+ this implementation makes sure that they are always in correct
+ order hence this simple code. */
+ *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
+ for (i = 0; i < argc; i++)
+ (*parsed_types)[i] = i;
+
+ *parsed_num = argc;
+}
+
+/* Formats arguments to a string and returns it after allocating memory
+ for it. It must be remembered to free it later. */
+
+char *silc_format(char *fmt, ...)
+{
+ va_list args;
+ static char buf[8192];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+ va_end(args);
+
+ return strdup(buf);
+}
+
+/* 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) {
+ case SILC_ID_SERVER:
+ {
+ SilcServerID *server_id = (SilcServerID *)id;
+ if (server_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ 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) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, server_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(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) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ case SILC_ID_CLIENT:
+ {
+ SilcClientID *client_id = (SilcClientID *)id;
+ if (client_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ 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) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, client_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
+ _PUT_STRING(rid, tmp);
+ memset(tmp, 0, sizeof(tmp));
+ 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]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ case SILC_ID_CHANNEL:
+ {
+ SilcChannelID *channel_id = (SilcChannelID *)id;
+ if (channel_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ 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) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, channel_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(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) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ }
+
+ return rid;
+}
+#undef _PUT_STRING
+
+/* Compares two strings. Strings may include wildcards '*' and '?'.