Merged from silc_1_0_branch.
[silc.git] / lib / silcutil / silcutil.c
index acdf3a9bd178211bf42e742d3fd2119a8bcf0866..8c9064891527f6199d346681f9d3a38cf3cb0d53 100644 (file)
@@ -78,18 +78,23 @@ int silc_check_line(char *buf)
   return 0;
 }
 
-/* Returns current time as string. */
+/* Returns time as string.  If the the `timeval' is non-zero that
+   value is returned as string.  If it is zero the current time of the
+   local machine is returned. */
 
-char *silc_get_time()
+const char *silc_get_time(SilcUInt32 timeval)
 {
   time_t curtime;
   char *return_time;
 
-  curtime = time(NULL);
+  if (!timeval)
+    curtime = time(NULL);
+  else
+    curtime = (time_t)timeval;
   return_time = ctime(&curtime);
   return_time[strlen(return_time) - 1] = '\0';
 
-  return return_time;
+  return (const char *)return_time;
 }
 
 /* Converts string to capital characters. */
@@ -384,7 +389,7 @@ int silc_string_compare(char *string1, char *string2)
   slen2 = strlen(string2);
 
   /* See if they are same already */
-  if (!strncmp(string1, string2, strlen(string2)))
+  if (!strncmp(string1, string2, slen2) && slen2 == slen1)
     return TRUE;
 
   if (slen2 < slen1)
@@ -652,12 +657,26 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
 
   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
     strncat(string, "M", 1);
-
+  
   if (mode & SILC_CHANNEL_MODE_CIPHER)
-    strncat(string, cipher, strlen(cipher));
-
+    strncat(string, "c", 1);
+  
   if (mode & SILC_CHANNEL_MODE_HMAC)
-    strncat(string, hmac, strlen(hmac));
+    strncat(string, "h", 1);
+
+  if (mode & SILC_CHANNEL_MODE_CIPHER) {
+    if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
+      strncat(string, " ", 1);
+      strncat(string, cipher, strlen(cipher));
+    }
+  }
+
+  if (mode & SILC_CHANNEL_MODE_HMAC) {
+    if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
+      strncat(string, " ", 1);
+      strncat(string, hmac, strlen(hmac));
+    }
+  }
 
   /* Rest of mode is ignored */
 
@@ -668,7 +687,7 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
 
 char *silc_client_chumode(SilcUInt32 mode)
 {
-  char string[4];
+  char string[64];
 
   if (!mode)
     return NULL;
@@ -690,6 +709,9 @@ char *silc_client_chumode(SilcUInt32 mode)
   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
     strncat(string, "r", 1);
 
+  if (mode & SILC_CHANNEL_UMODE_QUIET)
+    strncat(string, "q", 1);
+
   return strdup(string);
 }
 
@@ -697,7 +719,7 @@ char *silc_client_chumode(SilcUInt32 mode)
 
 char *silc_client_chumode_char(SilcUInt32 mode)
 {
-  char string[4];
+  char string[64];
 
   if (!mode)
     return NULL;
@@ -710,6 +732,9 @@ char *silc_client_chumode_char(SilcUInt32 mode)
   if (mode & SILC_CHANNEL_UMODE_CHANOP)
     strncat(string, "@", 1);
 
+  if (mode & SILC_CHANNEL_UMODE_QUIET)
+    strncat(string, "&", 1);
+
   return strdup(string);
 }
 
@@ -777,11 +802,12 @@ bool silc_parse_version_string(const char *version,
   /* Take protocol version */
 
   maj = atoi(cp);
-  cp = strchr(cp, '.');
-  if (cp) {
-    min = atoi(cp + 1);
-    cp++;
-  }
+  if (!strchr(cp, '.'))
+    return FALSE;
+  cp = strchr(cp, '.') + 1;
+  if (!cp || !(*cp))
+    return FALSE;
+  min = atoi(cp);
 
   memset(buf, 0, sizeof(buf));
   snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
@@ -796,14 +822,18 @@ bool silc_parse_version_string(const char *version,
 
   maj = 0;
   min = 0;
-  cp = strchr(cp, '-');
-  if (!cp)
+  if (!strchr(cp, '-'))
+    return FALSE;
+  cp = strchr(cp, '-') + 1;
+  if (!cp || !(*cp))
     return FALSE;
 
-  maj = atoi(cp + 1);
-  cp = strchr(cp, '.');
-  if (cp)
-    min = atoi(cp + 1);
+  maj = atoi(cp);
+  if (strchr(cp, '.')) {
+    cp = strchr(cp, '.') + 1;
+    if (cp && *cp)
+      min = atoi(cp);
+  }
 
   memset(buf, 0, sizeof(buf));
   snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
@@ -816,11 +846,10 @@ bool silc_parse_version_string(const char *version,
 
   /* Take vendor string */
 
-  cp++;
-  if (cp) {
-    cp = strchr(cp, '.');
-    if (cp && cp + 1 && vendor_version)
-      *vendor_version = strdup(cp + 1);
+  if (strchr(cp, '.')) {
+    cp = strchr(cp, '.') + 1;
+    if (cp && *cp && vendor_version)
+      *vendor_version = strdup(cp);
   }
 
   return TRUE;
@@ -852,11 +881,12 @@ SilcUInt32 silc_version_to_num(const char *version)
 char *silc_get_input(const char *prompt, bool echo_off)
 {
 #ifdef SILC_UNIX
+  int fd;
+  char input[2048];
+
   if (echo_off) {
     char *ret = NULL;
 #ifdef HAVE_TERMIOS_H
-    char input[2048];
-    int fd;
     struct termios to;
     struct termios to_old;
 
@@ -872,8 +902,10 @@ char *silc_get_input(const char *prompt, bool echo_off)
     tcgetattr(fd, &to);
     to_old = to;
 
-    /* Echo OFF */
+    /* Echo OFF, and assure we can prompt and get input */
     to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+    to.c_lflag |= ICANON;
+    to.c_cc[VMIN] = 255;
     tcsetattr(fd, TCSANOW, &to);
 
     memset(input, 0, sizeof(input));
@@ -883,6 +915,7 @@ char *silc_get_input(const char *prompt, bool echo_off)
 
     if ((read(fd, input, sizeof(input))) < 0) {
       fprintf(stderr, "silc: %s\n", strerror(errno));
+      tcsetattr(fd, TCSANOW, &to_old);
       return NULL;
     }
 
@@ -898,15 +931,11 @@ char *silc_get_input(const char *prompt, bool echo_off)
     tcsetattr(fd, TCSANOW, &to_old);
     signal(SIGINT, SIG_DFL);
 
-    ret = silc_calloc(strlen(input), sizeof(char));
-    memcpy(ret, input, strlen(input));
+    ret = silc_memdup(input, strlen(input));
     memset(input, 0, sizeof(input));
 #endif /* HAVE_TERMIOS_H */
     return ret;
   } else {
-    char input[2048];
-    int fd;
-
     fd = open("/dev/tty", O_RDONLY);
     if (fd < 0) {
       fprintf(stderr, "silc: %s\n", strerror(errno));
@@ -961,11 +990,11 @@ bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
 /* Status message structure. Messages are defined below. */
 typedef struct {
   SilcStatus status;
-  char *message;
+  const char *message;
 } SilcStatusMessage;
 
 #define STAT(x) SILC_STATUS_ERR_##x
-const SilcStatusMessage silc_status_messages[] = {
+static const SilcStatusMessage silc_status_messages[] = {
 
   { STAT(NO_SUCH_NICK),      "There was no such nickname" },
   { STAT(NO_SUCH_CHANNEL),   "There was no such channel" },
@@ -989,7 +1018,7 @@ const SilcStatusMessage silc_status_messages[] = {
   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
   { STAT(PERM_DENIED),       "Permission denied" },
-  { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
+  { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
   { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
   { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
   { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
@@ -1011,13 +1040,16 @@ const SilcStatusMessage silc_status_messages[] = {
   { STAT(BAD_SERVER_ID), "Server ID is not valid" },
   { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
   { STAT(BAD_VERSION), "Bad version" },
+  { STAT(TIMEDOUT), "Service timed out" },
+  { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
+  { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
 
   { 0, NULL }
 };
 
 /* Returns status message string */
 
-char *silc_get_status_message(unsigned char status)
+const char *silc_get_status_message(unsigned char status)
 {
   int i;
 
@@ -1031,3 +1063,105 @@ char *silc_get_status_message(unsigned char status)
 
   return silc_status_messages[i].message;
 }
+
+static const char *packet_name[] = {
+  "NONE",
+  "DISCONNECT",
+  "SUCCESS",
+  "FAILURE",
+  "REJECT",
+  "NOTIFY",
+  "ERROR",
+  "CHANNEL MESSAGE",
+  "CHANNEL KEY",
+  "PRIVATE MESSAGE",
+  "PRIVATE MESSAGE KEY",
+  "COMMAND",
+  "COMMAND REPLY",
+  "KEY EXCHANGE",
+  "KEY EXCHANGE 1",
+  "KEY EXCHANGE 2",
+  "CONNECTION AUTH REQUEST",
+  "CONNECTION AUTH",
+  "NEW ID",
+  "NEW CLIENT",
+  "NEW SERVER",
+  "NEW CHANNEL",
+  "REKEY",
+  "REKEY_DONE",
+  "HEARTBEAT",
+  "KEY AGREEMENT",
+  "RESUME ROUTER",
+  "FTP",
+  "RESUME CLIENT",
+};
+
+/* Returns packet type name */
+
+const char *silc_get_packet_name(unsigned char type)
+{
+  if (type >= SILC_PACKET_MAX)
+    return "RESERVED";
+  if (type >= SILC_PACKET_PRIVATE)
+    return "PRIVATE RANGE";
+  if (type > (sizeof(packet_name) / sizeof(*packet_name)))
+    return "UNKNOWN";
+  return packet_name[type];
+}
+
+static const char *command_name[] = {
+  "NONE",
+  "WHOIS",
+  "WHOWAS",
+  "IDENTIFY",
+  "NICK",
+  "LIST",
+  "TOPIC",
+  "INVITE",
+  "QUIT",
+  "KILL",
+  "INFO",
+  "STATS",
+  "PING",
+  "OPER",
+  "JOIN",
+  "MOTD",
+  "UMODE",
+  "CMODE",
+  "CUMODE",
+  "KICK",
+  "BAN",
+  "DETACH",
+  "WATCH",
+  "SILCOPER",
+  "LEAVE",
+  "USERS",
+  "GETKEY",
+  "SERVICE",
+};
+
+/* Returns command name */
+
+const char *silc_get_command_name(unsigned char command)
+{
+  if (command >= SILC_COMMAND_RESERVED)
+    return "RESERVED";
+  if (command >= SILC_COMMAND_PRIVATE)
+    return "PRIVATE RANGE";
+  if (command > (sizeof(command_name) / sizeof(*command_name)))
+    return "UNKNOWN";
+  return command_name[command];
+}
+
+/* Return TRUE if `smaller' is smaller than `bigger'. */
+
+bool silc_compare_timeval(struct timeval *smaller, 
+                         struct timeval *bigger)
+{
+  if ((smaller->tv_sec < bigger->tv_sec) ||
+      ((smaller->tv_sec == bigger->tv_sec) &&
+       (smaller->tv_usec < bigger->tv_usec)))
+    return TRUE;
+
+  return FALSE;
+}