$OpenBSD: patch-src_pysilc_callbacks_c,v 1.3 2007/10/02 17:35:48 martynas Exp $
--- src/pysilc_callbacks.c.orig	Sun Jul  9 20:18:27 2006
+++ src/pysilc_callbacks.c	Sun Jul  1 22:52:11 2007
@@ -46,6 +46,81 @@
 #define PYSILC_SILCBUFFER_TO_PYLIST(source, destination, Type) \
     do { } while (0);
 
+static void _pysilc_client_running(SilcClient client,
+                                   void *context)
+{
+    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
+    PyObject *callback = NULL, *result = NULL;
+
+    callback = PyObject_GetAttrString((PyObject *)pyclient, "running");
+    if (!PyCallable_Check(callback))
+        goto cleanup;
+    if ((result = PyObject_CallObject(callback, NULL)) == 0)
+        PyErr_Print();
+
+cleanup:
+    Py_XDECREF(callback);
+    Py_XDECREF(result);
+}
+
+static void _pysilc_client_connect_callback(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcClientConnectionStatus status,
+                                            SilcStatus error,
+                                            const char *message,
+                                            void *context)
+{
+    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
+    PyObject *args = NULL, *callback = NULL, *result = NULL;
+
+    if ((status == SILC_CLIENT_CONN_SUCCESS) || (status == SILC_CLIENT_CONN_SUCCESS_RESUME)) {
+        if (error != SILC_STATUS_OK) {
+            // TODO: raise an exception and abort
+            // call silc_client_close_connection(client, conn);
+            pyclient->silcconn = NULL;
+            goto cleanup;
+        }
+
+        pyclient->silcconn = conn;
+
+        callback = PyObject_GetAttrString((PyObject *)pyclient, "connected");
+        if (!PyCallable_Check(callback))
+            goto cleanup;
+        if ((result = PyObject_CallObject(callback, NULL)) == 0)
+            PyErr_Print();
+    }
+    else if (status == SILC_CLIENT_CONN_DISCONNECTED) {
+        if (status != SILC_STATUS_OK) {
+            // TODO: raise an exception and abort
+            // call silc_client_close_connection(client, conn);
+        }
+
+        // TODO: we're not letting the user know about ClientConnection atm.
+        pyclient->silcconn = NULL;
+        callback = PyObject_GetAttrString((PyObject *)pyclient, "disconnected");
+        if (!PyCallable_Check(callback))
+            goto cleanup;
+
+        if (!(args = Py_BuildValue("(s)", message)))
+            goto cleanup;
+        if ((result = PyObject_CallObject(callback, args)) == 0)
+            PyErr_Print();
+    }
+    else {
+        callback = PyObject_GetAttrString((PyObject *)pyclient, "failure");
+        if (!PyCallable_Check(callback))
+            goto cleanup;
+        // TODO: pass on protocol, failure parameters
+        if ((result = PyObject_CallObject(callback, NULL)) == 0)
+            PyErr_Print();
+    }
+
+cleanup:
+    Py_XDECREF(args);
+    Py_XDECREF(callback);
+    Py_XDECREF(result);
+}
+
 static void _pysilc_client_callback_say(SilcClient client,
                                         SilcClientConnection conn,
                                         SilcClientMessageType type,
@@ -72,10 +147,11 @@ cleanup:    
 
 static void _pysilc_client_callback_command(SilcClient client, 
                                             SilcClientConnection conn,
-                                            SilcClientCommandContext cmd_context, 
-                                            bool success,
+                                            SilcBool success,
                                             SilcCommand command, 
-                                            SilcStatus status) 
+                                            SilcStatus status,
+                                            SilcUInt32 argc,
+                                            unsigned char **argv)
 {
     PyObject *callback = NULL, *args = NULL, *result = NULL;
     
@@ -155,78 +231,26 @@ cleanup:
     Py_XDECREF(result);
 }
 
-static void _pysilc_client_callback_connected(SilcClient client, 
-                                              SilcClientConnection conn,
-                                              SilcClientConnectionStatus status)
-{
-    PyObject *result = NULL, *callback = NULL;
-    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
-    
-    if (status != SILC_STATUS_OK) {
-        // TODO: raise an exception and abort
-        // call silc_client_close_connection(client, conn);
-        pyclient->silcconn = NULL;
-        goto cleanup;
-    }
-
-
-    pyclient->silcconn = conn;
-
-    callback = PyObject_GetAttrString((PyObject *)pyclient, "connected");
-    if (!PyCallable_Check(callback))
-        goto cleanup;
-    if ((result = PyObject_CallObject(callback, NULL)) == 0)
-        PyErr_Print();
-cleanup:
-    Py_XDECREF(callback);
-    Py_XDECREF(result);
-}
-
-static void _pysilc_client_callback_disconnected(SilcClient client,
-                                                 SilcClientConnection conn,
-                                                 SilcStatus status,
-                                                 const char *message)
-{
-    PyObject *result = NULL, *callback = NULL, *args = NULL;
-    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
-    
-    if (status != SILC_STATUS_OK) {
-        // TODO: raise an exception and abort
-        // call silc_client_close_connection(client, conn);
-    }
-    
-    // TODO: we're not letting the user know about ClientConnection atm.
-    pyclient->silcconn = NULL;
-    callback = PyObject_GetAttrString((PyObject *)pyclient, "disconnected");
-    if (!PyCallable_Check(callback))
-        goto cleanup;
-
-    if (!(args = Py_BuildValue("(s)", message)))
-        goto cleanup;
-    if ((result = PyObject_CallObject(callback, args)) == 0)
-        PyErr_Print();    
-cleanup:
-    Py_XDECREF(callback);
-    Py_XDECREF(args);
-    Py_XDECREF(result);
-}
-
 typedef struct _PySilcClient_Callback_Join_Context
 {
    char *channel_name;
    char *topic;
    char *hmac_name;
+   char *cipher;
    PyObject *pychannel;
    SilcUInt32 channel_mode;
-   SilcUInt32 user_limit; 
+   SilcUInt32 user_limit;
+   SilcHashTableList *user_list;
 } PySilcClient_Callback_Join_Context;
 
 static void _pysilc_client_callback_command_reply_join_finished(SilcClient client,
                                                                 SilcClientConnection conn,
-                                                                SilcClientEntry *user_list,
-                                                                SilcUInt32 user_count,
-                                                                void * context)
+                                                                void *context)
 {
+    SilcUInt32 user_count;
+    SilcClientEntry user;
+    SilcChannelUser user_channel;
+
     PyObject *result = NULL, *callback = NULL, *args = NULL;
     PyObject *pytopic = NULL, *pyhmac_name = NULL, *users = NULL;
     PySilcClient_Callback_Join_Context *join_context = NULL;
@@ -243,13 +267,16 @@ static void _pysilc_client_callback_command_reply_join
 
     // extract all the users
     SilcUInt32 i = 0;
-    users = PyTuple_New(user_count);    
-    for (i = 0; i < user_count; i++) {
-        PyObject *u = PySilcUser_New(user_list[i]);
+    user_count = silc_hash_table_count(join_context->user_list->ht);
+    users = PyTuple_New(user_count);
+    i = 0;
+    while (silc_hash_table_get(join_context->user_list, (void *)&user, (void *)&user_channel)) {
+        PyObject *u = PySilcUser_New(user);
         PyTuple_SetItem(users, i, u);
+        i++;
         // TODO: we don't DECREF because PyTuple doesn't incr ref count.
     }
-    
+
     // prepare some possibly NULL values
     if (join_context->topic == NULL) {
         pytopic = Py_None;
@@ -292,14 +319,18 @@ static void _pysilc_client_callback_command_reply_join
     Py_XDECREF(args);
     Py_XDECREF(result);
 }                                                                
-    
-    
+
+
 static void _pysilc_client_callback_notify(SilcClient client, 
                                            SilcClientConnection conn,
                                            SilcNotifyType type, ...) {
 
     PyObject *args = NULL, *result = NULL, *pyuser = NULL, *pychannel = NULL;
     PyObject *callback = NULL, *pyarg = NULL;
+    SilcIdType idtype;
+    SilcUInt32 mode;
+    void *entry = NULL;
+    char *topic = NULL;
 
     PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
     va_list va;
@@ -357,30 +388,34 @@ static void _pysilc_client_callback_notify(SilcClient 
         break;
     case SILC_NOTIFY_TYPE_TOPIC_SET:
         PYSILC_GET_CALLBACK_OR_BREAK("notify_topic_set");
-        int idtype = va_arg(va, int);
-        void *entry = va_arg(va, void *);
-        char *topic = va_arg(va, char *);
+        idtype = va_arg(va, int);
+        entry = va_arg(va, void *);
+        topic = va_arg(va, char *);
         PYSILC_NEW_CHANNEL_OR_BREAK(va_arg(va, SilcChannelEntry), pychannel);
 
         switch (idtype) {
-        case SILC_ID_CLIENT:
-            PYSILC_NEW_USER_OR_BREAK(entry, pyuser);
-            if ((args = Py_BuildValue("(iOOs)", idtype, pyuser, pychannel, topic)) == NULL)
+            case SILC_ID_CLIENT:
+                PYSILC_NEW_USER_OR_BREAK(entry, pyarg);
                 break;
-            if ((result = PyObject_CallObject(callback, args)) == 0)
-                PyErr_Print();
-            break;
-        case SILC_ID_CHANNEL:
-            PYSILC_NEW_CHANNEL_OR_BREAK(entry, pyarg);
-            if ((args = Py_BuildValue("(iOOs)", idtype, pyarg, pychannel, topic)) == NULL)
+            case SILC_ID_CHANNEL:
+                PYSILC_NEW_CHANNEL_OR_BREAK(entry, pyarg);
                 break;
-            if ((result = PyObject_CallObject(callback, args)) == 0)
-                PyErr_Print();                
-            break;
-        case SILC_ID_SERVER:
-            // TODO: Unimplemented
-            break;
+            case SILC_ID_SERVER:
+                pyarg = Py_None;
+                Py_INCREF(pyarg); // TODO: no server type
+                break;
         }
+        
+        args = Py_BuildValue("(iOOs)", 
+            idtype, 
+            pyarg, 
+            pychannel, 
+            topic);
+            
+        if (args == NULL)
+            break;
+        if ((result = PyObject_CallObject(callback, args)) == 0)
+            PyErr_Print();
         break;
 
     case SILC_NOTIFY_TYPE_NICK_CHANGE:
@@ -394,30 +429,80 @@ static void _pysilc_client_callback_notify(SilcClient 
         break;
 
     case SILC_NOTIFY_TYPE_CMODE_CHANGE:
-        /*
-        if (!PyCallable_Check(pyclient->notify_cmode_change))
-            break;
+        PYSILC_GET_CALLBACK_OR_BREAK("notify_cmode_change");
+        idtype = va_arg(va, int);
+        entry = va_arg(va, void *);
+        mode = va_arg(va, SilcUInt32);
+        char *cipher_name = va_arg(va, char *);
+        char *hmac_name = va_arg(va, char *);
+        char *passphrase = va_arg(va, char *);
+        SilcPublicKey founder_key = va_arg(va, SilcPublicKey);
+        SilcBuffer channel_pubkeys = va_arg(va, SilcBuffer);
         PYSILC_NEW_CHANNEL_OR_BREAK(va_arg(va, SilcChannelEntry), pychannel);
-        PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyuser);
-        if ((args = Py_BuildValue("(IOO)", status, pychannel, pyuser)) == NULL)
+        
+        switch (idtype) { 
+            case SILC_ID_CLIENT:
+                PYSILC_NEW_USER_OR_BREAK(entry, pyarg);
+                break;
+            case SILC_ID_CHANNEL:
+                PYSILC_NEW_CHANNEL_OR_BREAK(entry, pyarg);
+                break;
+            case SILC_ID_SERVER:
+                pyarg = Py_None; // TODO: no server objects
+                Py_INCREF(Py_None);
+                break;
+        }
+
+        args = Py_BuildValue("(iOOissss)",
+            idtype,
+            pyarg, 
+            mode,
+            cipher_name,
+            hmac_name,
+            passphrase,
+            Py_None,
+            Py_None,
+            pychannel);
+
+        if (args == NULL)
             break;
             
-        result = PyObject_CallObject(pyclient->notify_cmode_change, args);
-        */
-        // TODO: wrong implementation
+        if ((result = PyObject_CallObject(callback, args)) == 0)
+            PyErr_Print();
         break;
 
     case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
-        /*
-        if (!PyCallable_Check(pyclient->notify_cumode_change))
-            break;
+        PYSILC_GET_CALLBACK_OR_BREAK("notify_cumode_change");
+        idtype = va_arg(va, int);
+        entry = va_arg(va, void *);
+        mode = va_arg(va, SilcUInt32);
         PYSILC_NEW_CHANNEL_OR_BREAK(va_arg(va, SilcChannelEntry), pychannel);
         PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyuser);
-        if ((args = Py_BuildValue("(IOO)", status, pychannel, pyuser)) == NULL)
+        switch (idtype) { 
+        case SILC_ID_CLIENT:
+            PYSILC_NEW_USER_OR_BREAK(entry, pyarg);
             break;
-        result = PyObject_CallObject(pyclient->notify_cumode_change, args);
-        */
-        // TODO: wrong implementation
+        case SILC_ID_CHANNEL:
+            PYSILC_NEW_CHANNEL_OR_BREAK(entry, pyarg);
+            break;
+        case SILC_ID_SERVER:
+            pyarg = Py_None; // TODO: no server objects
+            Py_INCREF(Py_None);
+            break;
+        }
+        
+        args = Py_BuildValue("(iOiOO)",
+                             idtype,
+                             pyarg,
+                             mode,
+                             pychannel,
+                             pyuser);
+             
+        if (args == NULL) 
+            break;
+        
+        if ((result = PyObject_CallObject(callback, args)) == 0)
+            PyErr_Print();
         break;
 
     case SILC_NOTIFY_TYPE_MOTD:
@@ -444,9 +529,8 @@ static void _pysilc_client_callback_notify(SilcClient 
         
     case SILC_NOTIFY_TYPE_KICKED:
         PYSILC_GET_CALLBACK_OR_BREAK("notify_kicked");
-        char *message;        
-        PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyarg);            
-        message = va_arg(va, char *);
+        PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyarg);
+        char *message = va_arg(va, char *);
         PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyuser);
         PYSILC_NEW_CHANNEL_OR_BREAK(va_arg(va, SilcChannelEntry), pychannel);
         
@@ -457,7 +541,37 @@ static void _pysilc_client_callback_notify(SilcClient 
         break;
 
     case SILC_NOTIFY_TYPE_KILLED:
-        break; // TODO: Unimplemented
+        PYSILC_GET_CALLBACK_OR_BREAK("notify_killed");
+        PYSILC_NEW_USER_OR_BREAK(va_arg(va, SilcClientEntry), pyuser);
+        char *kill_message = va_arg(va, char *);
+        idtype = va_arg(va, int);
+        entry = va_arg(va, void *);
+        PYSILC_NEW_CHANNEL_OR_BREAK(va_arg(va, SilcChannelEntry), pychannel);
+        switch (idtype) { 
+        case SILC_ID_CLIENT:
+             PYSILC_NEW_USER_OR_BREAK(entry, pyarg);
+             break;
+        case SILC_ID_CHANNEL:
+            PYSILC_NEW_CHANNEL_OR_BREAK(entry, pyarg);
+            break;
+        case SILC_ID_SERVER:
+            pyarg = Py_None; // TODO: no server objects
+            Py_INCREF(Py_None);
+            break;
+        }
+
+        args = Py_BuildValue("(OsOO)",
+         pyuser, // client that was killed
+         kill_message,
+         pyarg, // the killer, either a SilcClient or SilcChannel or None
+         pychannel);
+ 
+        if (args == NULL) 
+            break;
+
+        if ((result = PyObject_CallObject(callback, args)) == 0)
+            PyErr_Print();
+        break;
         
     case SILC_NOTIFY_TYPE_ERROR:
         PYSILC_GET_CALLBACK_OR_BREAK("notify_error");
@@ -494,30 +608,27 @@ static void _pysilc_client_callback_notify(SilcClient 
 
 
 
-static void _pysilc_client_callback_command_reply(SilcClient client, 
+static void _pysilc_client_callback_command_reply(SilcClient client,
                                                   SilcClientConnection conn,
-                                                  SilcCommandPayload cmd_payload,
-                                                  bool success,
-                                                  SilcCommand command, 
-                                                  SilcStatus status, ...)
+                                                  SilcCommand command,
+                                                  SilcStatus status,
+                                                  SilcStatus error, va_list va)
 {
     PyObject *args = NULL, *result = NULL, *pyuser = NULL, *pychannel = NULL;
     PyObject *callback = NULL, *pyarg = NULL;
 
     PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
-    va_list va;
-    va_start(va, status);
     
-    if (!success) {
-        // we encounter an error, return the command and status
+    if (status != SILC_STATUS_OK) {
+        // we encounter an error, return the command and error
         callback = PyObject_GetAttrString((PyObject *)pyclient, 
                                           "command_reply_failed");
         if (!PyCallable_Check(callback))
             return;
         if (!(args = Py_BuildValue("(isis)", command, 
                                    silc_get_command_name(command), 
-                                   status,
-                                   silc_get_status_message(status)))) {
+                                   error,
+                                   silc_get_status_message(error)))) {
             Py_DECREF(callback);
             return;
         }
@@ -696,14 +807,11 @@ static void _pysilc_client_callback_command_reply(Silc
         memset(context, 0, sizeof(PySilcClient_Callback_Join_Context));
         if (!context)
             break;
-            
+
         char *tmpstr = NULL;
-        int ignored;
-        void *dummy;
         SilcUInt32 client_count;
         SilcBuffer client_list;
-        
-        
+
         tmpstr = va_arg(va, char *);
         if (tmpstr)
             context->channel_name = strdup(tmpstr);
@@ -711,27 +819,19 @@ static void _pysilc_client_callback_command_reply(Silc
         context->pychannel = pychannel;
         Py_INCREF(pychannel);
         context->channel_mode = va_arg(va, SilcUInt32);
-        ignored = va_arg(va, int);  // ignored: ignore        
-        dummy = va_arg(va, void *); // ignored: key_payload
-        dummy = va_arg(va, void *); // NULL
-        dummy = va_arg(va, void *); // NULL
+        context->user_list = va_arg(va, SilcHashTableList *);
         tmpstr = va_arg(va, char *);
         if (tmpstr)
             context->topic = strdup(tmpstr);
         tmpstr = va_arg(va, char *);
+            context->cipher = strdup(tmpstr);
+        tmpstr = va_arg(va, char *);
         if (tmpstr)
             context->hmac_name = strdup(tmpstr);
-        client_count = va_arg(va, SilcUInt32);
-        client_list = va_arg(va, SilcBuffer);
-        dummy = va_arg(va, void *); // TODO: SilcBuffer client_mode_list
-        dummy = va_arg(va, void *); // TODO: SilcPublicKey founder_key
-        dummy = va_arg(va, void *); // TODO: SilcBuffer channel_pubkeys
         context->user_limit = va_arg(va, SilcUInt32);
-            
-        silc_client_get_clients_by_list(client, conn, 
-                                        client_count, client_list,
-                                        _pysilc_client_callback_command_reply_join_finished,
-                                        context);
+
+        _pysilc_client_callback_command_reply_join_finished(client, conn, context);
+
         break;
     }
     case SILC_COMMAND_MOTD:
@@ -846,7 +946,7 @@ static void _pysilc_client_callback_command_reply(Silc
         if (channel && channel->user_list) {
             silc_hash_table_list(channel->user_list, &hash_list);
             while (silc_hash_table_get(&hash_list, (void *)&user, (void *)&user_channel)) {
-                cached = silc_client_get_client_by_id(client, conn, user->id);
+                cached = silc_client_get_client_by_id(client, conn, &(user->id));
                 if (cached) {
                     u = PySilcUser_New(cached);
                     PyTuple_SetItem(pyuser, i, u);
@@ -880,60 +980,37 @@ cleanup:
     Py_XDECREF(pyuser);
 }
 
-static void _pysilc_client_callback_verify_key(SilcClient client, 
+static void _pysilc_client_callback_verify_key(SilcClient client,
                                                SilcClientConnection conn,
-                                               SilcSocketType conn_type, 
-                                               unsigned char *pk,
-                                               SilcUInt32 pk_len, 
-                                               SilcSKEPKType pk_type,
-                                               SilcVerifyPublicKey completion, 
+                                               SilcConnectionType conn_type,
+                                               SilcPublicKey public_key,
+                                               SilcVerifyPublicKey completion,
                                                void *context)
 {
     // TODO: implement me
     completion(TRUE, context);   
 }
 
-static void _pysilc_client_callback_get_auth_method(SilcClient client, 
+static void _pysilc_client_callback_get_auth_method(SilcClient client,
                                                     SilcClientConnection conn,
-                                                    char *hostname, 
+                                                    char *hostname,
                                                     SilcUInt16 port,
-                                                    SilcGetAuthMeth completion, 
+                                                    SilcAuthMethod auth_method,
+                                                    SilcGetAuthMeth completion,
                                                     void *context)
 {
     // TODO: implement this properly
-    completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
+    completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
 }
 
-static void _pysilc_client_callback_failure(SilcClient client, 
-                                            SilcClientConnection conn,
-                                            SilcProtocol protocol, 
-                                            void *failure)
+static void _pysilc_client_callback_key_agreement(SilcClient client,
+                                                  SilcClientConnection conn,
+                                                  SilcClientEntry client_entry,
+                                                  const char *hostname,
+                                                  SilcUInt16 protocol,
+                                                  SilcUInt16 port)
 {
-    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
-    PyObject *callback = NULL, *result = NULL;
-    
-    callback = PyObject_GetAttrString((PyObject *)pyclient, "failure");
-    if (!PyCallable_Check(callback))
-        goto cleanup;
-    // TODO: pass on protocol, failure parameters
-    if ((result = PyObject_CallObject(callback, NULL)) == 0)
-        PyErr_Print();
-cleanup:
-    Py_XDECREF(callback);
-    Py_XDECREF(result);
-}
-
-
-static bool _pysilc_client_callback_key_agreement(SilcClient client, 
-                                            SilcClientConnection conn,
-                                            SilcClientEntry client_entry, 
-                                            const char *hostname,
-                                            SilcUInt16 port, 
-                                            SilcKeyAgreementCallback *completion,
-                                            void **context)
-{
     // TODO :implement me
-    return FALSE;
 }                                        
 
 static void _pysilc_client_callback_ftp(SilcClient client,
@@ -973,25 +1050,3 @@ cleanup:
     Py_XDECREF(callback);
     Py_XDECREF(result);
 }
-
-static void _pysilc_client_callback_detach(SilcClient client, 
-                                            SilcClientConnection conn,
-                                            const unsigned char *detach_data,
-                                            SilcUInt32 detach_data_len)
-{
-    PYSILC_GET_CLIENT_OR_DIE(client, pyclient);
-    PyObject *result = NULL, *callback = NULL, *args = NULL;
-    callback = PyObject_GetAttrString((PyObject *)pyclient, "detach");
-    if (!PyCallable_Check(callback))
-        goto cleanup;
-        
-    if (!(args = Py_BuildValue("(s#)", detach_data, detach_data_len)))
-        goto cleanup;
-    if ((result = PyObject_CallObject(callback, args)) == 0)
-        PyErr_Print();    
-    
-cleanup:
-    Py_XDECREF(callback);
-    Py_XDECREF(args);
-    Py_XDECREF(result);
-}                                            
