static gboolean infinoted_plugin_document_stream_process_send_chat_message( InfinotedPluginDocumentStreamStream* stream, const gchar** data, gsize* len) { guint16 text_len; const gchar* text; if(*len < 2) return FALSE; text_len = *(guint16*)(*data); *data += 2; *len -= 2; if(*len < text_len) return FALSE; text = *data; *data += text_len; *len -= text_len; if(!INF_IS_CHAT_BUFFER(stream->buffer)) { infinoted_plugin_document_stream_send_error( stream, "Not a chat session" ); } else { infinoted_plugin_document_stream_chat_add_message(stream, text, text_len); } return TRUE; }
/** * infd_chat_filesystem_format_write: * @storage: A #InfdFilesystemStorage. * @path: Storage path where to write the session to. * @buffer: The #InfChatBuffer to write. * @error: Location to store error information, if any, or %NULL. * * Writes the given buffer into the filesystem storage at @path. If * successful, the session can then be read back with * infd_chat_filesystem_format_read(). If the function fails, %FALSE is * returned and @error is set. * * Returns: %TRUE on success or %FALSE on error. */ gboolean infd_chat_filesystem_format_write(InfdFilesystemStorage* storage, const gchar* path, InfChatBuffer* buffer, GError** error) { FILE* stream; xmlDocPtr doc; xmlNodePtr root; xmlErrorPtr xmlerror; g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE); g_return_val_if_fail(path != NULL, FALSE); g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* Open stream before exporting buffer to XML so possible errors are * catched earlier. */ stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfChat", path, "w", NULL, error ); if(stream == NULL) return FALSE; root = xmlNewNode(NULL, (const xmlChar*)"inf-chat-session"); doc = xmlNewDoc((const xmlChar*)"1.0"); xmlDocSetRootElement(doc, root); /* TODO: At this point, we should tell libxml2 to use * infd_filesystem_storage_stream_write() instead of fwrite(), * to prevent C runtime mixups. */ if(xmlDocFormatDump(stream, doc, 1) == -1) { xmlerror = xmlGetLastError(); infd_filesystem_storage_stream_close(stream); xmlFreeDoc(doc); g_set_error_literal( error, g_quark_from_static_string("LIBXML2_OUTPUT_ERROR"), xmlerror->code, xmlerror->message ); return FALSE; } infd_filesystem_storage_stream_close(stream); xmlFreeDoc(doc); return TRUE; }
/** * inf_chat_buffer_get_message: * @buffer: A #InfChatBuffer. * @n: The index of the message to obtain. * * Returns the message with the given index from the buffer. The oldest * message in the buffer has index 0, and the most recent one has index * inf_chat_buffer_get_n_messages() - 1. * * Returns: The #InfChatBufferMessage with the given index. */ const InfChatBufferMessage* inf_chat_buffer_get_message(InfChatBuffer* buffer, guint n) { InfChatBufferPrivate* priv; g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), NULL); g_return_val_if_fail(n < inf_chat_buffer_get_n_messages(buffer), NULL); priv = INF_CHAT_BUFFER_PRIVATE(buffer); return &priv->messages[ (priv->first_message + n) % priv->size ]; }
static void infinoted_plugin_document_stream_sync_chat( InfinotedPluginDocumentStreamStream* stream) { InfChatBuffer* buffer; guint n_messages; guint i; const InfChatBufferMessage* message; g_assert(INF_IS_CHAT_BUFFER(stream->buffer)); buffer = INF_CHAT_BUFFER(stream->buffer); n_messages = inf_chat_buffer_get_n_messages(buffer); for(i = 0; i < n_messages; ++i) { message = inf_chat_buffer_get_message(buffer, i); infinoted_plugin_document_stream_chat_send_message(stream, message); } }
/** * inf_chat_buffer_add_userpart_message: * @buffer: A #InfChatBuffer. * @user: A #InfUser who wrote the message. * @time: The time at which the user has written the message. * @flags: Flags to set for the message to add. * * Adds a new userpart message to the chat buffer. If the buffer is full * (meaning the number of messages in the buffer equals its size), then an * old message will get discarded. If the message to be added is older than * all other messages in the buffer, then it will not be added at all. */ void inf_chat_buffer_add_userpart_message(InfChatBuffer* buffer, InfUser* user, time_t time, InfChatBufferMessageFlags flags) { InfChatBufferMessage msg; g_return_if_fail(INF_IS_CHAT_BUFFER(buffer)); g_return_if_fail(INF_IS_USER(user)); msg.type = INF_CHAT_BUFFER_MESSAGE_USERPART; msg.user = user; msg.text = NULL; msg.length = 0; msg.time = time; msg.flags = flags; g_signal_emit(buffer, chat_buffer_signals[ADD_MESSAGE], 0, &msg); }
/** * inf_chat_buffer_add_emote_message: * @buffer: A #InfChatBuffer. * @by: A #InfUser who wrote the message. * @message: The message text. * @length: The length of @message, in bytes. * @time: The time at which the user has written the message. * @flags: Flags to set for the message to add. * * Adds a new emote message to the chat buffer. If the buffer is full * (meaning the number of messages in the buffer equals its size), then an * old message will get discarded. If the message to be added is older than * all other messages in the buffer, then it will not be added at all. */ void inf_chat_buffer_add_emote_message(InfChatBuffer* buffer, InfUser* by, const gchar* message, gsize length, time_t time, InfChatBufferMessageFlags flags) { InfChatBufferMessage msg; g_return_if_fail(INF_IS_CHAT_BUFFER(buffer)); g_return_if_fail(INF_IS_USER(by)); g_return_if_fail(message != NULL); msg.type = INF_CHAT_BUFFER_MESSAGE_EMOTE; msg.user = by; /* cast const away without warning */ msg.text = *(gchar**) (gpointer) &message; msg.length = length; msg.time = time; msg.flags = flags; g_signal_emit(buffer, chat_buffer_signals[ADD_MESSAGE], 0, &msg); }
/** * inf_chat_buffer_get_size: * @buffer: A #InfChatBuffer. * * Returns the size of the chat buffer, which is the maximum number of * messages that can be stored in the buffer. * * Returns: The number of messages in the chat buffer. */ guint inf_chat_buffer_get_size(InfChatBuffer* buffer) { g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), 0); return INF_CHAT_BUFFER_PRIVATE(buffer)->size; }
/** * inf_chat_buffer_get_n_messages: * @buffer: A #InfChatBuffer. * * Returns the number of messages in the buffer. * * Returns: The number of messages in the buffer. */ guint inf_chat_buffer_get_n_messages(InfChatBuffer* buffer) { g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), 0); return INF_CHAT_BUFFER_PRIVATE(buffer)->num_messages; }
static void infinoted_plugin_document_stream_stop( InfinotedPluginDocumentStreamStream* stream, gboolean send_stop) { guint32 comm; InfSession* session; if(send_stop) { comm = 5; /* STOP */ if(!infinoted_plugin_document_stream_send(stream, &comm, 4)) return; } if(stream->user != NULL) { g_assert(stream->proxy != NULL); g_object_get(G_OBJECT(stream->proxy), "session", &session, NULL); inf_session_set_user_status(session, stream->user, INF_USER_UNAVAILABLE); g_object_unref(session); g_object_unref(stream->user); stream->user = NULL; } if(stream->proxy != NULL) { g_object_unref(stream->proxy); stream->proxy = NULL; } if(stream->buffer != NULL) { if(INF_TEXT_IS_BUFFER(stream->buffer)) { inf_signal_handlers_disconnect_by_func( G_OBJECT(stream->buffer), G_CALLBACK(infinoted_plugin_document_stream_text_inserted_cb), stream ); inf_signal_handlers_disconnect_by_func( G_OBJECT(stream->buffer), G_CALLBACK(infinoted_plugin_document_stream_text_erased_cb), stream ); } else if(INF_IS_CHAT_BUFFER(stream->buffer)) { inf_signal_handlers_disconnect_by_func( G_OBJECT(stream->buffer), G_CALLBACK(infinoted_plugin_document_stream_chat_add_message_cb), stream ); } g_object_unref(stream->buffer); stream->buffer = NULL; } if(stream->subscribe_request != NULL) { inf_signal_handlers_disconnect_by_func( G_OBJECT(stream->subscribe_request), G_CALLBACK(infinoted_plugin_document_stream_subscribe_func), stream ); stream->subscribe_request = NULL; } if(stream->user_request != NULL) { inf_signal_handlers_disconnect_by_func( G_OBJECT(stream->user_request), G_CALLBACK(infinoted_plugin_document_stream_user_join_func), stream ); stream->user_request = NULL; } }
/** * infd_chat_filesystem_format_read: * @storage: A #InfdFilesystemStorage. * @path: Storage path to retrieve the session from. * @buffer: An empty #InfTextBuffer to use as the new session's buffer. * @error: Location to store error information, if any, or %NULL. * * Reads a chat session from @path in @storage. The file is expected to have * been saved with infd_chat_filesystem_format_write() before. The @buffer * parameter should be an empty #InfChatBuffer, and the document will be * written into this buffer. If the function succeeds, the buffer can be used * to create an #InfChatSession with inf_chat_session_new(). If the function * fails, %FALSE is returned and @error is set. * * Returns: %TRUE on success or %FALSE on error. */ gboolean infd_chat_filesystem_format_read(InfdFilesystemStorage* storage, const gchar* path, InfChatBuffer* buffer, GError** error) { FILE* stream; gchar* full_path; gchar* uri; xmlDocPtr doc; xmlErrorPtr xmlerror; xmlNodePtr root; xmlNodePtr child; gboolean result; g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE); g_return_val_if_fail(path != NULL, FALSE); g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* TODO: Use a SAX parser for better performance */ full_path = NULL; stream = infd_filesystem_storage_open( INFD_FILESYSTEM_STORAGE(storage), "InfChat", path, "r", &full_path, error ); if(stream == NULL) { g_free(full_path); return FALSE; } uri = g_filename_to_uri(full_path, NULL, error); g_free(full_path); if(uri == NULL) return FALSE; doc = xmlReadIO( infd_chat_filesystem_format_read_read_func, infd_chat_filesystem_format_read_close_func, stream, uri, "UTF-8", XML_PARSE_NOWARNING | XML_PARSE_NOERROR ); g_free(uri); if(doc == NULL) { xmlerror = xmlGetLastError(); g_set_error( error, g_quark_from_static_string("LIBXML2_PARSER_ERROR"), xmlerror->code, _("Error parsing XML in file \"%s\": [%d]: %s"), path, xmlerror->line, xmlerror->message ); result = FALSE; } else { root = xmlDocGetRootElement(doc); if(strcmp((const char*)root->name, "inf-chat-session") != 0) { g_set_error( error, infd_chat_filesystem_format_error_quark(), INFD_CHAT_FILESYSTEM_FORMAT_ERROR_NOT_A_CHAT_SESSION, _("Error processing file \"%s\": %s"), path, _("The document is not a chat session") ); result = FALSE; } else { result = TRUE; } xmlFreeDoc(doc); } if(result == FALSE) return FALSE; return TRUE; }