/** * inf_text_gtk_viewport_set_active_user: * @viewport: A #InfTextGtkViewport. * @user: A user from @viewport's user table, or %NULL. * * Sets the user for which perspective to draw the viewport. The cursor * position for teh active user is not draws since it is assumed that the * viewport's "real" scrollbars match the active user's position. */ void inf_text_gtk_viewport_set_active_user(InfTextGtkViewport* viewport, InfTextUser* user) { InfTextGtkViewportPrivate* priv; InfTextUser* active_user; g_return_if_fail(INF_TEXT_GTK_IS_VIEWPORT(viewport)); g_return_if_fail(user == NULL || INF_TEXT_IS_USER(user)); priv = INF_TEXT_GTK_VIEWPORT_PRIVATE(viewport); g_return_if_fail( user == NULL || inf_user_table_lookup_user_by_id( priv->user_table, inf_user_get_id(INF_USER(user)) ) == INF_USER(user) ); if(priv->active_user != NULL) { active_user = priv->active_user; priv->active_user = NULL; inf_text_gtk_viewport_user_added(viewport, active_user); } if(user != NULL) { inf_text_gtk_viewport_user_removed(viewport, user); } priv->active_user = user; g_object_notify(G_OBJECT(viewport), "active-user"); }
static InfAdoptedUser* inf_adopted_session_user_from_request_xml(InfAdoptedSession* session, xmlNodePtr xml, GError** error) { InfUserTable* user_table; InfUser* user; guint user_id; user_table = inf_session_get_user_table(INF_SESSION(session)); if(!inf_xml_util_get_attribute_uint_required(xml, "user", &user_id, error)) return FALSE; /* User ID 0 means no user */ if(user_id == 0) return NULL; user = inf_user_table_lookup_user_by_id(user_table, user_id); if(user == NULL) { g_set_error( error, inf_adopted_session_error_quark, INF_ADOPTED_SESSION_ERROR_NO_SUCH_USER, _("No such user with user ID '%u'"), user_id ); return NULL; } g_assert(INF_ADOPTED_IS_USER(user)); return INF_ADOPTED_USER(user); }
static gboolean inf_adopted_session_process_xml_sync(InfSession* session, InfXmlConnection* connection, const xmlNodePtr xml, GError** error) { InfAdoptedSessionClass* session_class; InfAdoptedRequest* request; InfAdoptedUser* user; InfAdoptedRequestLog* log; if(strcmp((const char*)xml->name, "sync-request") == 0) { session_class = INF_ADOPTED_SESSION_GET_CLASS(session); g_assert(session_class->xml_to_request != NULL); request = session_class->xml_to_request( INF_ADOPTED_SESSION(session), xml, NULL, /* TODO: Diff to previous request, if any. */ TRUE, error ); if(request == NULL) return FALSE; user = INF_ADOPTED_USER( inf_user_table_lookup_user_by_id( inf_session_get_user_table(session), inf_adopted_request_get_user_id(request) ) ); log = inf_adopted_user_get_request_log(user); if(inf_adopted_session_validate_request(log, request, error) == FALSE) { g_object_unref(request); return FALSE; } inf_adopted_request_log_add_request(log, request); g_object_unref(request); return TRUE; } return INF_SESSION_CLASS(parent_class)->process_xml_sync( session, connection, xml, error ); }
/* Breadcasts a request N times - makes only sense for undo and redo requests, * so that's the only thing we offer API for. */ static void inf_adopted_session_broadcast_n_requests(InfAdoptedSession* session, InfAdoptedRequest* request, guint n) { InfAdoptedSessionPrivate* priv; InfAdoptedSessionClass* session_class; InfUserTable* user_table; guint user_id; InfUser* user; InfAdoptedSessionLocalUser* local; xmlNodePtr xml; priv = INF_ADOPTED_SESSION_PRIVATE(session); session_class = INF_ADOPTED_SESSION_GET_CLASS(session); g_assert(session_class->request_to_xml != NULL); user_table = inf_session_get_user_table(INF_SESSION(session)); user_id = inf_adopted_request_get_user_id(request); user = inf_user_table_lookup_user_by_id(user_table, user_id); g_assert(user != NULL); local = inf_adopted_session_lookup_local_user( session, INF_ADOPTED_USER(user) ); g_assert(local != NULL); xml = xmlNewNode(NULL, (const xmlChar*)"request"); session_class->request_to_xml( session, xml, request, local->last_send_vector, FALSE ); if(n > 1) inf_xml_util_set_attribute_uint(xml, "num", n); inf_session_send_to_subscriptions(INF_SESSION(session), xml); inf_adopted_state_vector_free(local->last_send_vector); local->last_send_vector = inf_adopted_state_vector_copy( inf_adopted_request_get_vector(request) ); /* Add this request to last send vector if it increases vector time * (-> affects buffer). */ if(inf_adopted_request_affects_buffer(request) == TRUE) inf_adopted_state_vector_add(local->last_send_vector, user_id, n); inf_adopted_session_stop_noop_timer(session, local); }
void Gobby::ChatSessionView::set_active_user(InfUser* user) { g_assert( user == NULL || inf_user_table_lookup_user_by_id( inf_session_get_user_table(INF_SESSION(m_session)), inf_user_get_id(INF_USER(user))) == INF_USER(user)); inf_gtk_chat_set_active_user(m_chat, user); active_user_changed(user); }
static gboolean infc_session_proxy_handle_user_rejoin(InfcSessionProxy* proxy, InfXmlConnection* connection, xmlNodePtr xml, GError** error) { InfcSessionProxyPrivate* priv; InfSessionClass* session_class; GArray* array; InfUser* user; const GParameter* idparam; GParameter* param; guint id; gboolean result; guint i; priv = INFC_SESSION_PROXY_PRIVATE(proxy); session_class = INF_SESSION_GET_CLASS(priv->session); array = session_class->get_xml_user_props(priv->session, connection, xml); /* Find rejoining user first */ idparam = inf_session_lookup_user_property( (const GParameter*)array->data, array->len, "id" ); if(idparam == NULL) { g_set_error( error, inf_request_error_quark(), INF_REQUEST_ERROR_NO_SUCH_ATTRIBUTE, _("Request does not contain required attribute 'id'") ); goto error; } id = g_value_get_uint(&idparam->value); user = inf_user_table_lookup_user_by_id( inf_session_get_user_table(priv->session), id ); if(user == NULL) { g_set_error( error, inf_user_error_quark(), INF_USER_ERROR_NO_SUCH_USER, _("No such user with ID %u"), id ); goto error; } /* Set local flag if the join was requested by us (seq is present in * server response). */ param = inf_session_get_user_property(array, "flags"); g_assert(!G_IS_VALUE(¶m->value)); /* must not have been set already */ g_value_init(¶m->value, INF_TYPE_USER_FLAGS); if(xmlHasProp(xml, (const xmlChar*)"seq") != NULL) g_value_set_flags(¶m->value, INF_USER_LOCAL); else g_value_set_flags(¶m->value, 0); /* Set connection. If none was given, use publisher connection */ param = inf_session_get_user_property(array, "connection"); if(!G_IS_VALUE(¶m->value)) { g_value_init(¶m->value, INF_TYPE_XML_CONNECTION); g_value_set_object(¶m->value, G_OBJECT(connection)); } result = session_class->validate_user_props( priv->session, (const GParameter*)array->data, array->len, user, error ); if(result == FALSE) goto error; /* Set properties on the found user object, performing the rejoin */ g_object_freeze_notify(G_OBJECT(user)); for(i = 0; i < array->len; ++ i) { param = &g_array_index(array, GParameter, i); /* Don't set ID because the ID is the same anyway (we did the user lookup * by it). The "id" property is construct only anyway. */ if(strcmp(param->name, "id") != 0) g_object_set_property(G_OBJECT(user), param->name, ¶m->value); } /* TODO: Set user status to available, if the server did not send the * status property? Require the status property being set on a rejoin? * Make sure it is not unavailable? */ g_object_thaw_notify(G_OBJECT(user)); for(i = 0; i < array->len; ++ i) g_value_unset(&g_array_index(array, GParameter, i).value); g_array_free(array, TRUE); infc_session_proxy_succeed_user_request(proxy, xml, user); return TRUE; error: for(i = 0; i < array->len; ++ i) g_value_unset(&g_array_index(array, GParameter, i).value); g_array_free(array, TRUE); return FALSE; }
static gboolean perform_test(guint max_total_log_size, InfTextChunk* initial, GSList* users, GSList* requests, GError** error) { InfTextBuffer* buffer; InfCommunicationManager* manager; InfIo* io; InfTextSession* session; InfAdoptedAlgorithm* algorithm; InfUserTable* user_table; InfTextUser* user; gchar* user_name; GSList* item; xmlNodePtr request; gboolean result; GError* local_error; guint verify_user_id; InfAdoptedUser* verify_user; guint verify_log_size; gint verify_can_undo; gint verify_can_redo; InfAdoptedRequestLog* log; guint log_size; buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8")); inf_text_buffer_insert_chunk(buffer, 0, initial, NULL); manager = inf_communication_manager_new(); io = INF_IO(inf_standalone_io_new()); user_table = inf_user_table_new(); local_error = NULL; for(item = users; item != NULL; item = g_slist_next(item)) { user_name = g_strdup_printf("User_%u", GPOINTER_TO_UINT(item->data)); user = INF_TEXT_USER( g_object_new( INF_TEXT_TYPE_USER, "id", GPOINTER_TO_UINT(item->data), "name", user_name, "status", INF_USER_ACTIVE, "flags", 0, NULL ) ); g_free(user_name); inf_user_table_add_user(user_table, INF_USER(user)); g_object_unref(user); } session = INF_TEXT_SESSION( g_object_new( INF_TEXT_TYPE_SESSION, "communication-manager", manager, "buffer", buffer, "io", io, "user_table", user_table, "max-total-log-size", max_total_log_size, NULL ) ); algorithm = inf_adopted_session_get_algorithm(INF_ADOPTED_SESSION(session)); g_object_unref(io); g_object_unref(manager); g_object_unref(user_table); g_object_unref(buffer); for(item = requests; item != NULL; item = item->next) { request = (xmlNodePtr)item->data; if(strcmp((const char*)request->name, "request") == 0) { /* Request */ result = inf_communication_object_received( INF_COMMUNICATION_OBJECT(session), NULL, request, &local_error ); if(local_error != NULL) goto fail; } else { /* TODO: Make an extra function out of this: */ /* Verify */ result = inf_xml_util_get_attribute_uint_required( request, "user", &verify_user_id, &local_error ); if(result == FALSE) goto fail; verify_user = INF_ADOPTED_USER( inf_user_table_lookup_user_by_id(user_table, verify_user_id) ); if(verify_user == NULL) { g_set_error( error, inf_test_text_cleanup_error_quark(), INF_TEST_TEXT_CLEANUP_USER_UNAVAILABLE, "User ID '%u' not available", verify_user_id ); goto fail; } result = inf_xml_util_get_attribute_uint( request, "log-size", &verify_log_size, &local_error ); if(local_error) goto fail; if(result) { log = inf_adopted_user_get_request_log(INF_ADOPTED_USER(verify_user)); log_size = inf_adopted_request_log_get_end(log) - inf_adopted_request_log_get_begin(log); if(verify_log_size != log_size) { g_set_error( error, inf_test_text_cleanup_error_quark(), INF_TEST_TEXT_CLEANUP_VERIFY_FAILED, "Log size does not match; got %u, but expected %u", log_size, verify_log_size ); goto fail; } } result = inf_xml_util_get_attribute_int( request, "can-undo", &verify_can_undo, &local_error ); if(local_error) goto fail; if(result) { result = inf_adopted_algorithm_can_undo(algorithm, verify_user); if(result != verify_can_undo) { g_set_error( error, inf_test_text_cleanup_error_quark(), INF_TEST_TEXT_CLEANUP_VERIFY_FAILED, "can-undo does not match; got %d, but expected %d", (guint)result, verify_can_undo ); goto fail; } } result = inf_xml_util_get_attribute_int( request, "can-redo", &verify_can_redo, &local_error ); if(local_error) goto fail; if(result) { result = inf_adopted_algorithm_can_redo(algorithm, verify_user); if(result != verify_can_redo) { g_set_error( error, inf_test_text_cleanup_error_quark(), INF_TEST_TEXT_CLEANUP_VERIFY_FAILED, "can-redo does not match; got %d, but expected %d", (guint)result, verify_can_redo ); goto fail; } } } } g_object_unref(session); return TRUE; fail: g_object_unref(session); if(local_error) g_propagate_error(error, local_error); return FALSE; }
static gboolean infd_note_plugin_text_read_user(InfUserTable* user_table, xmlNodePtr node, GError** error) { guint id; gdouble hue; xmlChar* name; gboolean result; InfUser* user; if(!inf_xml_util_get_attribute_uint_required(node, "id", &id, error)) return FALSE; if(!inf_xml_util_get_attribute_double_required(node, "hue", &hue, error)) return FALSE; name = inf_xml_util_get_attribute_required(node, "name", error); if(name == NULL) return FALSE; if(inf_user_table_lookup_user_by_id(user_table, id) != NULL) { g_set_error( error, g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"), INFD_NOTE_PLUGIN_TEXT_ERROR_USER_EXISTS, "User with ID %u exists already", id ); result = FALSE; } else { if(inf_user_table_lookup_user_by_name(user_table, (const gchar*)name)) { g_set_error( error, g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"), INFD_NOTE_PLUGIN_TEXT_ERROR_USER_EXISTS, "User with name `%s' exists already", (const gchar*)name ); result = FALSE; } else { user = INF_USER( g_object_new( INF_TEXT_TYPE_USER, "id", id, "name", name, "hue", hue, NULL ) ); inf_user_table_add_user(user_table, user); g_object_unref(user); result = TRUE; } } xmlFree(name); return result; }
static gboolean infd_note_plugin_text_read_buffer(InfTextBuffer* buffer, InfUserTable* user_table, xmlNodePtr node, GError** error) { xmlNodePtr child; guint author; gchar* content; gboolean result; gboolean res; InfUser* user; gsize bytes; guint chars; g_assert(inf_text_buffer_get_length(buffer) == 0); for(child = node->children; child != NULL; child = child->next) { if(child->type != XML_ELEMENT_NODE) continue; if(strcmp((const gchar*)child->name, "segment") == 0) { res = inf_xml_util_get_attribute_uint_required( child, "author", &author, error ); if(res == FALSE) { result = FALSE; break; } if(author != 0) { user = inf_user_table_lookup_user_by_id(user_table, author); if(user == NULL) { g_set_error( error, g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"), INFD_NOTE_PLUGIN_TEXT_ERROR_NO_SUCH_USER, "User with ID %u does not exist", author ); result = FALSE; break; } } else { user = NULL; } content = inf_xml_util_get_child_text(child, &bytes, &chars, error); if(!content) { result = FALSE; break; } if(*content != '\0') { /* TODO: Use inf_text_buffer_append when we have it */ inf_text_buffer_insert_text( buffer, inf_text_buffer_get_length(buffer), content, bytes, chars, user ); } g_free(content); } else { infd_note_plugin_text_session_unexpected_node(child, error); result = FALSE; break; } } if(child == NULL) result = TRUE; return result; }