updates.
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index 16415900889e9d758e0eb05ad89f1f77f0ee7bfd..6bbf81a555d7a98c0f57b055cefad95577af90d4 100644 (file)
@@ -81,7 +81,8 @@ void silc_say_error(char *msg, ...)
 
 void silc_channel_message(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, SilcChannelEntry channel,
-                         SilcMessageFlags flags, char *msg)
+                         SilcMessageFlags flags, const unsigned char *message,
+                         SilcUInt32 message_len)
 {
   SILC_SERVER_REC *server;
   SILC_NICK_REC *nick;
@@ -89,7 +90,7 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   
   SILC_LOG_DEBUG(("Start"));
 
-  if (!msg)
+  if (!message)
     return;
 
   server = conn == NULL ? NULL : conn->context;
@@ -108,13 +109,13 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   if (flags & SILC_MESSAGE_FLAG_ACTION)
     printformat_module("fe-common/silc", server, channel->channel_name,
                       MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, 
-                       nick == NULL ? "[<unknown>]" : nick->nick, msg);
+                       nick == NULL ? "[<unknown>]" : nick->nick, message);
   else if (flags & SILC_MESSAGE_FLAG_NOTICE)
     printformat_module("fe-common/silc", server, channel->channel_name,
                       MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, 
-                       nick == NULL ? "[<unknown>]" : nick->nick, msg);
+                       nick == NULL ? "[<unknown>]" : nick->nick, message);
   else
-    signal_emit("message public", 6, server, msg,
+    signal_emit("message public", 6, server, message,
                nick == NULL ? "[<unknown>]" : nick->nick,
                nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
                chanrec->name, nick);
@@ -125,7 +126,8 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
 
 void silc_private_message(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, SilcMessageFlags flags,
-                         char *msg)
+                         const unsigned char *message,
+                         SilcUInt32 message_len)
 {
   SILC_SERVER_REC *server;
   char userhost[256];
@@ -137,7 +139,7 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
   if (sender->username)
     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
             sender->username, sender->hostname);
-  signal_emit("message private", 4, server, msg,
+  signal_emit("message private", 4, server, message,
              sender->nickname ? sender->nickname : "[<unknown>]",
              sender->username ? userhost : NULL);
 }
@@ -317,7 +319,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       signal_emit("message topic", 5, server, channel->channel_name,
                  tmp, server_entry->server_name, 
                  server_entry->server_name);
-    } else {
+    } else if (idtype == SILC_ID_CHANNEL) {
       channel = (SilcChannelEntry)entry;
       signal_emit("message topic", 5, server, channel->channel_name,
                  tmp, channel->channel_name, channel->channel_name);
@@ -333,6 +335,9 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     client_entry = va_arg(va, SilcClientEntry);
     client_entry2 = va_arg(va, SilcClientEntry);
+
+    if (!strcmp(client_entry->nickname, client_entry2->nickname))
+      break;
     
     memset(userhost, 0, sizeof(userhost));
     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
@@ -383,7 +388,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
                         channel->channel_name, tmp ? tmp : "removed all",
                         server_entry->server_name);
-    } else {
+    } else if (idtype == SILC_ID_CHANNEL) {
       channel2 = (SilcChannelEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
@@ -437,7 +442,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
                         channel->channel_name, client_entry2->nickname, 
                         tmp ? tmp : "removed all",
                         server_entry->server_name);
-    } else {
+    } else if (idtype == SILC_ID_CHANNEL) {
       channel2 = (SilcChannelEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
@@ -516,11 +521,27 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     client_entry = va_arg(va, SilcClientEntry);
     tmp = va_arg(va, char *);
+    idtype = va_arg(va, int);
+    entry = va_arg(va, SilcClientEntry);
   
     if (client_entry == conn->local_entry) {
-      printformat_module("fe-common/silc", server, NULL,
-                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
-                        tmp ? tmp : "");
+      if (idtype == SILC_ID_CLIENT) {
+       client_entry2 = (SilcClientEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          client_entry2 ? client_entry2->nickname : "",
+                          tmp ? tmp : "");
+      } else if (idtype == SILC_ID_SERVER) {
+       server_entry = (SilcServerEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          server_entry->server_name, tmp ? tmp : "");
+      } else if (idtype == SILC_ID_CHANNEL) {
+       channel = (SilcChannelEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          channel->channel_name, tmp ? tmp : "");
+      }
     } else {
       list1 = nicklist_get_same_unique(SERVER(server), client_entry);
       for (list_tmp = list1; list_tmp != NULL; list_tmp = 
@@ -530,10 +551,26 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
        nicklist_remove(channel, nickrec);
       }
 
-      printformat_module("fe-common/silc", server, NULL,
-                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
-                        client_entry->nickname,
-                        tmp ? tmp : "");
+      if (idtype == SILC_ID_CLIENT) {
+       client_entry2 = (SilcClientEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          client_entry->nickname,
+                          client_entry2 ? client_entry2->nickname : "",
+                          tmp ? tmp : "");
+      } else if (idtype == SILC_ID_SERVER) {
+       server_entry = (SilcServerEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          client_entry->nickname,
+                          server_entry->server_name, tmp ? tmp : "");
+      } else if (idtype == SILC_ID_CHANNEL) {
+       channel = (SilcChannelEntry)entry;
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          client_entry->nickname,
+                          channel->channel_name, tmp ? tmp : "");
+      }
     }
     break;
 
@@ -591,23 +628,48 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
    or connecting failed.  This is also the first time application receives
    the SilcClientConnection object which it should save somewhere. */
 
-void silc_connect(SilcClient client, SilcClientConnection conn, int success)
+void silc_connect(SilcClient client, SilcClientConnection conn,
+                 SilcClientConnectionStatus status)
 {
   SILC_SERVER_REC *server = conn->context;
 
-  if (!server && !success) {
-    silc_client_close_connection(client, NULL, conn);
+  if (!server || status == SILC_CLIENT_CONN_ERROR) {
+    silc_client_close_connection(client, conn);
     return;
   }
 
-  if (success) {
+  switch (status) {
+  case SILC_CLIENT_CONN_SUCCESS:
+    /* We have successfully connected to server */
     server->connected = TRUE;
     signal_emit("event connected", 1, server);
-  } else {
+    break;
+
+  case SILC_CLIENT_CONN_SUCCESS_RESUME:
+    /* We have successfully resumed old detached session */
+    server->connected = TRUE;
+    signal_emit("event connected", 1, server);
+
+    /* If we resumed old session check whether we need to update 
+       our nickname */
+    if (strcmp(server->nick, conn->local_entry->nickname)) {
+      char *old;
+      old = g_strdup(server->nick);
+      server_change_nick(SERVER(server), conn->local_entry->nickname);
+      nicklist_rename_unique(SERVER(server), 
+                            conn->local_entry, server->nick,
+                            conn->local_entry, conn->local_entry->nickname);
+      signal_emit("message own_nick", 4, server, server->nick, old, "");
+      g_free(old);
+    }
+    break;
+
+  default:
     server->connection_lost = TRUE;
     if (server->conn)
       server->conn->context = NULL;
     server_disconnect(SERVER(server));
+    break;
   }
 }
 
@@ -619,6 +681,9 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn)
 
   SILC_LOG_DEBUG(("Start"));
 
+  if (!server || server->connection_lost)
+    return;
+
   if (server->conn && server->conn->local_entry) {
     nicklist_rename_unique(SERVER(server),
                           server->conn->local_entry, server->nick,
@@ -704,6 +769,7 @@ static void silc_client_join_get_users(SilcClient client,
   ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
   nicklist_set_own(CHANNEL(chanrec), ownnick);
   signal_emit("channel joined", 1, chanrec);
+  chanrec->entry = channel;
 
   if (chanrec->topic)
     printformat_module("fe-common/silc", server, channel->channel_name,
@@ -790,7 +856,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char buf[1024], *nickname, *username, *realname, *nick;
       unsigned char *fingerprint;
       SilcUInt32 idle, mode;
-      SilcBuffer channels;
+      SilcBuffer channels, user_modes;
       SilcClientEntry client_entry;
       
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
@@ -835,6 +901,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       mode = va_arg(vp, SilcUInt32);
       idle = va_arg(vp, SilcUInt32);
       fingerprint = va_arg(vp, unsigned char *);
+      user_modes = va_arg(vp, SilcBuffer);
       
       silc_parse_userfqdn(nickname, &nick, NULL);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
@@ -845,16 +912,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                         SILCTXT_WHOIS_REALNAME, realname);
       silc_free(nick);
 
-      if (channels) {
+      if (channels && user_modes) {
+       SilcUInt32 *umodes;
        SilcDList list = silc_channel_payload_parse_list(channels->data,
                                                         channels->len);
-       if (list) {
+       if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
+                                      &umodes)) {
          SilcChannelPayload entry;
+         int i = 0;
+
          memset(buf, 0, sizeof(buf));
          silc_dlist_start(list);
          while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
-           char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
            SilcUInt32 name_len;
+           char *m = silc_client_chumode_char(umodes[i++]);
            char *name = silc_channel_get_name(entry, &name_len);
            
            if (m)
@@ -867,6 +938,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
          printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                             SILCTXT_WHOIS_CHANNELS, buf);
          silc_channel_payload_list_free(list);
+         silc_free(umodes);
        }
       }
       
@@ -876,12 +948,28 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
            (mode & SILC_UMODE_ROUTER_OPERATOR)) {
          strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
-                "Server Operator " :
+                "Server Operator" :
                 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
-                "SILC Operator " : "[Unknown mode] ");
+                "SILC Operator" : "[Unknown mode]");
        }
        if (mode & SILC_UMODE_GONE)
-         strcat(buf, "away");
+         strcat(buf, " [away]");
+       if (mode & SILC_UMODE_INDISPOSED)
+         strcat(buf, " [indisposed]");
+       if (mode & SILC_UMODE_BUSY)
+         strcat(buf, " [busy]");
+       if (mode & SILC_UMODE_PAGE)
+         strcat(buf, " [page to reach]");
+       if (mode & SILC_UMODE_HYPER)
+         strcat(buf, " [hyper active]");
+       if (mode & SILC_UMODE_ROBOT)
+         strcat(buf, " [robot]");
+       if (mode & SILC_UMODE_ANONYMOUS)
+         strcat(buf, " [anonymous]");
+       if (mode & SILC_UMODE_BLOCK_PRIVMSG)
+         strcat(buf, " [blocks private messages]");
+       if (mode & SILC_UMODE_DETACHED)
+         strcat(buf, " [detached]");
 
        printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                           SILCTXT_WHOIS_MODES, buf);
@@ -1171,8 +1259,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        mode = silc_client_chumode_char(chu->mode);
        if (e->mode & SILC_UMODE_GONE)
          strcat(stat, "G");
-       else
+       else if (e->mode & SILC_UMODE_INDISPOSED)
+         strcat(stat, "I");
+       else if (e->mode & SILC_UMODE_BUSY)
+         strcat(stat, "B");
+       else if (e->mode & SILC_UMODE_PAGE)
+         strcat(stat, "P");
+       else if (e->mode & SILC_UMODE_HYPER)
          strcat(stat, "H");
+       else if (e->mode & SILC_UMODE_ROBOT)
+         strcat(stat, "R");
+       else if (e->mode & SILC_UMODE_ANONYMOUS)
+         strcat(stat, "?");
+       else
+         strcat(stat, "A");
        if (mode)
          strcat(stat, mode);
 
@@ -1758,6 +1858,13 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn,
   return FALSE;
 }
 
+/* Notifies application that file transfer protocol session is being
+   requested by the remote client indicated by the `client_entry' from
+   the `hostname' and `port'. The `session_id' is the file transfer
+   session and it can be used to either accept or reject the file
+   transfer request, by calling the silc_client_file_receive or
+   silc_client_file_close, respectively. */
+
 void silc_ftp(SilcClient client, SilcClientConnection conn,
              SilcClientEntry client_entry, SilcUInt32 session_id,
              const char *hostname, SilcUInt16 port)
@@ -1789,6 +1896,37 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
                       client_entry->nickname, hostname, portstr);
 }
 
+/* Delivers SILC session detachment data indicated by `detach_data' to the
+   application.  If application has issued SILC_COMMAND_DETACH command
+   the client session in the SILC network is not quit.  The client remains
+   in the network but is detached.  The detachment data may be used later
+   to resume the session in the SILC Network.  The appliation is
+   responsible of saving the `detach_data', to for example in a file.
+
+   The detachment data can be given as argument to the functions
+   silc_client_connect_to_server, or silc_client_add_connection when
+   creating connection to remote server, inside SilcClientConnectionParams
+   structure.  If it is provided the client library will attempt to resume
+   the session in the network.  After the connection is created
+   successfully, the application is responsible of setting the user
+   interface for user into the same state it was before detaching (showing
+   same channels, channel modes, etc).  It can do this by fetching the
+   information (like joined channels) from the client library. */
+
+void
+silc_detach(SilcClient client, SilcClientConnection conn,
+            const unsigned char *detach_data, SilcUInt32 detach_data_len)
+{
+  char file[256];
+
+  /* Save the detachment data to file. */
+
+  memset(file, 0, sizeof(file));
+  snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
+  silc_file_writefile(file, detach_data, detach_data_len);
+}
+
+
 /* SILC client operations */
 SilcClientOperations ops = {
   silc_say,
@@ -1805,4 +1943,5 @@ SilcClientOperations ops = {
   silc_failure,
   silc_key_agreement,
   silc_ftp,
+  silc_detach,
 };