From d94ce591f20f0a561a68b239ece14f7f8fd487d9 Mon Sep 17 00:00:00 2001 From: "bozo.kopic" Date: Sun, 22 May 2022 03:02:28 +0200 Subject: gtk4 rewrite --- src_c/main.c | 389 +++++++++++++++++++++++++++++++++++++++++++ src_c/mblaze.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src_c/mblaze.h | 59 +++++++ 3 files changed, 959 insertions(+) create mode 100644 src_c/main.c create mode 100644 src_c/mblaze.c create mode 100644 src_c/mblaze.h (limited to 'src_c') diff --git a/src_c/main.c b/src_c/main.c new file mode 100644 index 0000000..ec30a13 --- /dev/null +++ b/src_c/main.c @@ -0,0 +1,389 @@ +#include +#include "mblaze.h" + + +typedef struct { + GtkTreeStore *directories_store; + GtkTreeSelection *directories_selection; + GtkTreeStore *messages_store; + GtkTreeSelection *messages_selection; + GtkTextBuffer *message_buffer; +} app_data_t; + +typedef struct { + grefcount rc; + GtkTreeStore *store; + GtkTreeIter iter; +} tree_store_iter_data_t; + + +static gchar *get_message_status_icon(mbgui_message_status_t status) { + switch (status) { + case MBGUI_MSG_STATUS_SEEN: + return "mail-read"; + case MBGUI_MSG_STATUS_FLAGGED: + return "starred"; + case MBGUI_MSG_STATUS_UNSEEN: + return "mail-unread"; + case MBGUI_MSG_STATUS_TRASHED: + return "user-trash"; + case MBGUI_MSG_STATUS_VIRTUAL: + return NULL; + } + return NULL; +} + + +static gchar *get_selected_directory(app_data_t *data) { + GtkTreeIter iter; + + if (!gtk_tree_selection_get_selected( + data->directories_selection, + (GtkTreeModel **)&(data->directories_store), &iter)) + return NULL; + + gchar *result; + gtk_tree_model_get(GTK_TREE_MODEL(data->directories_store), &iter, 0, + &result, -1); + return result; +} + + +static gchar *get_selected_message(app_data_t *data) { + GtkTreeIter iter; + + if (!gtk_tree_selection_get_selected( + data->messages_selection, (GtkTreeModel **)&(data->messages_store), + &iter)) + return NULL; + + gchar *result; + gtk_tree_model_get(GTK_TREE_MODEL(data->messages_store), &iter, 0, &result, + -1); + return result; +} + + +static void on_get_message(gchar *path, gchar *message, gpointer user_data) { + app_data_t *data = user_data; + + if (!message || !message[0]) + return; + + gchar *selected_message = get_selected_message(data); + if (!selected_message) + return; + + int not_selected = g_strcmp0(path, selected_message); + g_free(selected_message); + if (not_selected) + return; + + gtk_text_buffer_set_text(data->message_buffer, message, -1); +} + + +static void on_messages_selection_changed(GtkTreeSelection *self, + gpointer user_data) { + app_data_t *data = user_data; + + gtk_text_buffer_set_text(data->message_buffer, "", 0); + + gchar *message = get_selected_message(data); + if (!message) + return; + + // TODO chech virtual + + mbgui_get_message(message, on_get_message, data); + g_free(message); +} + + +static void add_message(GtkTreeStore *store, mbgui_message_t *message, + GtkTreeIter *parent) { + GtkTreeIter iter; + gtk_tree_store_append(store, &iter, parent); + gtk_tree_store_set(store, &iter, 0, message->path->str, 1, + get_message_status_icon(message->status), 2, + message->subject->str, 3, message->sender->str, 4, + message->date->str, -1); + + for (mbgui_message_t *child = message->children; child; child = child->next) + add_message(store, child, &iter); +} + + +static void on_get_messages(gchar *directory, mbgui_message_t *messages, + gpointer user_data) { + app_data_t *data = user_data; + + gchar *selected_directory = get_selected_directory(data); + if (!selected_directory) + return; + + int not_selected = g_strcmp0(directory, selected_directory); + g_free(selected_directory); + if (not_selected) + return; + + for (mbgui_message_t *message = messages; message; message = message->next) + add_message(data->messages_store, message, NULL); +} + + +static void on_directories_selection_changed(GtkTreeSelection *self, + gpointer user_data) { + app_data_t *data = user_data; + + gtk_tree_store_clear(data->messages_store); + + gchar *directory = get_selected_directory(data); + if (!directory) + return; + + mbgui_get_messages(directory, on_get_messages, data); + g_free(directory); +} + + +static GtkWidget *create_directories(app_data_t *data) { + data->directories_store = + gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING); + + GtkCellRenderer *icon_renderer = gtk_cell_renderer_pixbuf_new(); + g_object_set(icon_renderer, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); + + GtkCellRenderer *left_renderer = gtk_cell_renderer_text_new(); + g_object_set(left_renderer, "xalign", 0.0, "xpad", 5, "mode", + GTK_CELL_RENDERER_MODE_INERT, NULL); + + GtkCellRenderer *right_renderer = gtk_cell_renderer_text_new(); + g_object_set(right_renderer, "xalign", 1.0, "mode", + GTK_CELL_RENDERER_MODE_INERT, NULL); + + GtkWidget *scrolled_window = gtk_scrolled_window_new(); + + GtkWidget *directories = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(data->directories_store)); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window), + directories); + + GtkTreeViewColumn *col_directory = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col_directory, "Directory"); + gtk_tree_view_column_set_expand(col_directory, TRUE); + gtk_tree_view_column_pack_start(col_directory, icon_renderer, FALSE); + gtk_tree_view_column_set_attributes(col_directory, icon_renderer, + "icon-name", 1, NULL); + gtk_tree_view_column_pack_start(col_directory, left_renderer, TRUE); + gtk_tree_view_column_set_attributes(col_directory, left_renderer, "text", 2, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(directories), col_directory); + + GtkTreeViewColumn *col_unseen = gtk_tree_view_column_new_with_attributes( + "Unseen", right_renderer, "text", 3, NULL); + gtk_tree_view_column_set_sizing(col_unseen, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_append_column(GTK_TREE_VIEW(directories), col_unseen); + + GtkTreeViewColumn *col_total = gtk_tree_view_column_new_with_attributes( + "Total", right_renderer, "text", 4, NULL); + gtk_tree_view_column_set_sizing(col_total, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_append_column(GTK_TREE_VIEW(directories), col_total); + + data->directories_selection = + gtk_tree_view_get_selection(GTK_TREE_VIEW(directories)); + gtk_tree_selection_set_mode(data->directories_selection, + GTK_SELECTION_SINGLE); + g_signal_connect(data->directories_selection, "changed", + G_CALLBACK(on_directories_selection_changed), data); + + return scrolled_window; +} + + +static GtkWidget *create_messages(app_data_t *data) { + data->messages_store = + gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING); + + GtkCellRenderer *icon_renderer = gtk_cell_renderer_pixbuf_new(); + g_object_set(icon_renderer, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); + + GtkCellRenderer *left_renderer = gtk_cell_renderer_text_new(); + g_object_set(left_renderer, "xalign", 0.0, "xpad", 5, "mode", + GTK_CELL_RENDERER_MODE_INERT, NULL); + + GtkWidget *scrolled_window = gtk_scrolled_window_new(); + + GtkWidget *messages = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(data->messages_store)); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window), + messages); + + GtkTreeViewColumn *col_subject = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col_subject, "Subject"); + gtk_tree_view_column_set_expand(col_subject, TRUE); + gtk_tree_view_column_pack_start(col_subject, icon_renderer, FALSE); + gtk_tree_view_column_set_attributes(col_subject, icon_renderer, "icon-name", + 1, NULL); + gtk_tree_view_column_pack_start(col_subject, left_renderer, TRUE); + gtk_tree_view_column_set_attributes(col_subject, left_renderer, "text", 2, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(messages), col_subject); + + GtkTreeViewColumn *col_sender = gtk_tree_view_column_new_with_attributes( + "Sender", left_renderer, "text", 3, NULL); + gtk_tree_view_column_set_sizing(col_sender, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_append_column(GTK_TREE_VIEW(messages), col_sender); + + GtkTreeViewColumn *col_date = gtk_tree_view_column_new_with_attributes( + "Date", left_renderer, "text", 4, NULL); + gtk_tree_view_column_set_sizing(col_date, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_append_column(GTK_TREE_VIEW(messages), col_date); + + data->messages_selection = + gtk_tree_view_get_selection(GTK_TREE_VIEW(messages)); + gtk_tree_selection_set_mode(data->messages_selection, GTK_SELECTION_SINGLE); + g_signal_connect(data->messages_selection, "changed", + G_CALLBACK(on_messages_selection_changed), data); + + return scrolled_window; +} + + +static GtkWidget *create_message(app_data_t *data) { + data->message_buffer = gtk_text_buffer_new(NULL); + + GtkWidget *scrolled_window = gtk_scrolled_window_new(); + + GtkWidget *message = gtk_text_view_new_with_buffer(data->message_buffer); + gtk_text_view_set_editable(GTK_TEXT_VIEW(message), FALSE); + gtk_text_view_set_monospace(GTK_TEXT_VIEW(message), TRUE); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window), + message); + + return scrolled_window; +} + + +static GtkWidget *create_window(GtkApplication *app, app_data_t *data) { + GtkWidget *window = gtk_application_window_new(app); + gtk_window_set_title(GTK_WINDOW(window), "mbgui"); + gtk_window_set_default_size(GTK_WINDOW(window), 600, 800); + + GtkWidget *hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + gtk_paned_set_position(GTK_PANED(hpaned), 400); + gtk_window_set_child(GTK_WINDOW(window), hpaned); + + GtkWidget *directories = create_directories(data); + gtk_paned_set_start_child(GTK_PANED(hpaned), directories); + gtk_paned_set_resize_start_child(GTK_PANED(hpaned), TRUE); + + GtkWidget *vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL); + gtk_paned_set_position(GTK_PANED(vpaned), 400); + gtk_paned_set_end_child(GTK_PANED(hpaned), vpaned); + gtk_paned_set_resize_end_child(GTK_PANED(hpaned), TRUE); + + GtkWidget *messages = create_messages(data); + gtk_paned_set_start_child(GTK_PANED(vpaned), messages); + gtk_paned_set_resize_start_child(GTK_PANED(vpaned), TRUE); + + GtkWidget *message = create_message(data); + gtk_paned_set_end_child(GTK_PANED(vpaned), message); + gtk_paned_set_resize_end_child(GTK_PANED(vpaned), TRUE); + + return window; +} + + +static void on_get_directory_unseen(gchar *directory, gsize unseen, + gpointer user_data) { + tree_store_iter_data_t *data = user_data; + + GString *unseen_str = g_string_sized_new(8); + g_string_printf(unseen_str, "%lu", unseen); + + gtk_tree_store_set(data->store, &(data->iter), 3, unseen_str->str, -1); + + g_string_free(unseen_str, TRUE); + if (g_ref_count_dec((grefcount *)data)) + g_free(data); +} + + +static void on_get_directory_total(gchar *directory, gsize total, + gpointer user_data) { + tree_store_iter_data_t *data = user_data; + + GString *total_str = g_string_sized_new(8); + g_string_printf(total_str, "%lu", total); + + gtk_tree_store_set(data->store, &(data->iter), 4, total_str->str, -1); + + g_string_free(total_str, TRUE); + if (g_ref_count_dec((grefcount *)data)) + g_free(data); +} + + +static void add_directory(GtkTreeStore *store, mbgui_directory_t *directory, + GtkTreeIter *parent) { + GtkTreeIter iter; + gtk_tree_store_append(store, &iter, parent); + gtk_tree_store_set(store, &iter, 0, + (directory->path ? directory->path->str : NULL), 1, + (directory->path ? "folder-documents" : "folder"), 2, + directory->name->str, -1); + + for (mbgui_directory_t *child = directory->children; child; + child = child->next) + add_directory(store, child, &iter); + + if (!directory->path) + return; + + tree_store_iter_data_t *data = g_malloc(sizeof(tree_store_iter_data_t)); + data->store = store; + data->iter = iter; + + g_ref_count_init((grefcount *)data); + mbgui_get_directory_unseen(directory->path->str, on_get_directory_unseen, + data); + + g_ref_count_inc((grefcount *)data); + mbgui_get_directory_total(directory->path->str, on_get_directory_total, + data); +} + + +static void on_get_directories(mbgui_directory_t *directories, + gpointer user_data) { + app_data_t *data = user_data; + + for (mbgui_directory_t *directory = directories; directory; + directory = directory->next) + add_directory(data->directories_store, directory, NULL); +} + + +static void on_command_line(GtkApplication *app, + GApplicationCommandLine *command_line, + gpointer user_data) { + app_data_t *data = g_malloc(sizeof(app_data_t)); + GtkWidget *window = create_window(app, data); + gtk_window_present(GTK_WINDOW(window)); + + gchar **argv = g_application_command_line_get_arguments(command_line, NULL); + mbgui_get_directories(argv, on_get_directories, data); + g_strfreev(argv); +} + + +int main(int argc, char **argv) { + GtkApplication *app = + gtk_application_new(NULL, G_APPLICATION_HANDLES_COMMAND_LINE); + g_signal_connect(app, "command-line", G_CALLBACK(on_command_line), NULL); + + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/src_c/mblaze.c b/src_c/mblaze.c new file mode 100644 index 0000000..f6ee2ce --- /dev/null +++ b/src_c/mblaze.c @@ -0,0 +1,511 @@ +#include +#include +#include +#include "mblaze.h" + + +typedef struct { + mbgui_get_directories_cb_t cb; + gpointer user_data; + mbgui_directory_t *directories; + GSubprocess *process; + GDataInputStream *stream; +} get_directories_data_t; + +typedef struct { + GString *directory; + mbgui_get_directory_total_cb_t cb; + gpointer user_data; + gsize total; + GSubprocess *process; + GDataInputStream *stream; +} get_directory_total_data_t; + +typedef struct { + GString *directory; + mbgui_get_directory_unseen_cb_t cb; + gpointer user_data; + gsize unseen; + GSubprocess *process; + GDataInputStream *stream; +} get_directory_unseen_data_t; + +typedef struct { + GString *directory; + mbgui_get_messages_cb_t cb; + gpointer user_data; + mbgui_message_t *messages; + gchar *line_buff[6]; + gsize line_buff_count; + gint mlist_stdout_fd; + gint mthread_stdout_fd; + gint mscan_stdout_fd; + GInputStream *mscan_stdout; + GDataInputStream *stream; +} get_messages_data_t; + +typedef struct { + GString *path; + mbgui_get_message_cb_t cb; + gpointer user_data; + gchar buff[1024]; + GString *message; + GSubprocess *process; +} get_message_data_t; + + +static void free_directories(mbgui_directory_t *directories) { + if (!directories) + return; + if (directories->path) + g_string_free(directories->path, TRUE); + if (directories->name) + g_string_free(directories->name, TRUE); + free_directories(directories->children); + free_directories(directories->next); + g_free(directories); +} + + +static void free_messages(mbgui_message_t *messages) { + if (!messages) + return; + if (messages->path) + g_string_free(messages->path, TRUE); + if (messages->subject) + g_string_free(messages->subject, TRUE); + if (messages->sender) + g_string_free(messages->sender, TRUE); + if (messages->date) + g_string_free(messages->date, TRUE); + free_messages(messages->children); + free_messages(messages->next); + g_free(messages); +} + + +static void free_get_directories_data(get_directories_data_t *data) { + free_directories(data->directories); + g_object_unref(data->stream); + g_object_unref(data->process); + g_free(data); +} + + +static void free_get_directory_total_data(get_directory_total_data_t *data) { + g_string_free(data->directory, TRUE); + g_object_unref(data->stream); + g_object_unref(data->process); + g_free(data); +} + + +static void free_get_directory_unseen_data(get_directory_unseen_data_t *data) { + g_string_free(data->directory, TRUE); + g_object_unref(data->stream); + g_object_unref(data->process); + g_free(data); +} + + +static void free_get_messages_data(get_messages_data_t *data) { + g_string_free(data->directory, TRUE); + free_messages(data->messages); + for (gsize i = 0; i < data->line_buff_count; ++i) + g_free(data->line_buff[i]); + if (data->stream) + g_object_unref(data->stream); + if (data->mscan_stdout) + g_object_unref(data->mscan_stdout); + if (data->mscan_stdout_fd >= 0) + g_close(data->mscan_stdout_fd, NULL); + if (data->mthread_stdout_fd >= 0) + g_close(data->mthread_stdout_fd, NULL); + if (data->mlist_stdout_fd >= 0) + g_close(data->mlist_stdout_fd, NULL); + free(data); +} + + +static void free_get_message_data(get_message_data_t *data) { + g_string_free(data->path, TRUE); + g_string_free(data->message, TRUE); + g_object_unref(data->process); + g_free(data); +} + + +static void reduce_directory(mbgui_directory_t *directory) { + for (mbgui_directory_t *child = directory->children; + child && !child->next && !directory->path; + child = directory->children) { + g_string_append_printf(directory->name, "/%s", child->name->str); + directory->path = child->path; + child->path = NULL; + directory->children = child->children; + child->children = NULL; + free_directories(child); + } + + for (mbgui_directory_t *child = directory->children; child; + child = child->next) + reduce_directory(child); +} + + +static mbgui_directory_t *reverse_directories(mbgui_directory_t *directories) { + mbgui_directory_t *reversed = NULL; + while (directories) { + mbgui_directory_t *next = directories->next; + directories->children = reverse_directories(directories->children); + directories->next = reversed; + reversed = directories; + directories = next; + } + return reversed; +} + + +static mbgui_directory_t *add_directory(mbgui_directory_t *directories, + gchar *path, gchar *name) { + if (*name != '/') + return directories; + + gsize index = 1; + while (name[index] && name[index] != '/') + ++index; + + if (name[index]) { + GString *subname = g_string_new_len(name + 1, index - 1); + + mbgui_directory_t *directory = directories; + while (directory && !g_string_equal(directory->name, subname)) + directory = directory->next; + + if (directory) { + g_string_free(subname, TRUE); + + } else { + directory = g_malloc(sizeof(mbgui_directory_t)); + directory->path = NULL; + directory->name = subname; + directory->children = NULL; + directory->next = directories; + } + + directory->children = + add_directory(directory->children, path, name + index); + return directory; + } + + mbgui_directory_t *directory = g_malloc(sizeof(mbgui_directory_t)); + directory->path = g_string_new(path); + directory->name = g_string_new(name + 1); + directory->children = NULL; + directory->next = directories; + return directory; +} + + +static gsize get_message_depth(gchar *line) { + gsize depth = 0; + + if (line[0] == '.' && line[1] == '.') { + for (gchar *i = line + 2; g_ascii_isdigit(*i); ++i) + depth = depth * 10 + (*i - '0'); + + } else { + for (gchar *i = line; *i; ++i) { + if (*i == ' ') + depth += 1; + } + } + + return depth; +} + + +static mbgui_message_t *reverse_messages(mbgui_message_t *messages) { + mbgui_message_t *reversed = NULL; + while (messages) { + mbgui_message_t *next = messages->next; + messages->children = reverse_messages(messages->children); + messages->next = reversed; + reversed = messages; + messages = next; + } + return reversed; +} + + +static mbgui_message_t *add_message(mbgui_message_t *messages, gsize depth, + gchar **lines) { + if (depth && messages) { + messages->children = add_message(messages->children, depth - 1, lines); + return messages; + } + + mbgui_message_t *message = g_malloc(sizeof(mbgui_message_t)); + message->path = g_string_new(lines[0]); + message->status = lines[1][0]; + message->subject = g_string_new(lines[2]); + message->sender = g_string_new(lines[3]); + message->date = g_string_new(lines[4]); + message->children = NULL; + message->next = messages; + + return message; +} + + +static void on_get_directories_read_line(GObject *source_object, + GAsyncResult *result, + gpointer user_data) { + get_directories_data_t *data = user_data; + + gchar *line = + g_data_input_stream_read_line_finish(data->stream, result, NULL, NULL); + + if (!line) { + data->directories = reverse_directories(data->directories); + for (mbgui_directory_t *directory = data->directories; directory; + directory = directory->next) { + g_string_prepend_c(directory->name, '/'); + reduce_directory(directory); + } + data->cb(data->directories, data->user_data); + free_get_directories_data(data); + return; + } + + data->directories = add_directory(data->directories, line, line); + g_free(line); + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_directories_read_line, data); +} + + +static void on_get_directory_total_read_line(GObject *source_object, + GAsyncResult *result, + gpointer user_data) { + get_directory_total_data_t *data = user_data; + + gchar *line = + g_data_input_stream_read_line_finish(data->stream, result, NULL, NULL); + + if (!line) { + data->cb(data->directory->str, data->total, data->user_data); + free_get_directory_total_data(data); + return; + } + + data->total += 1; + g_free(line); + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_directory_total_read_line, data); +} + + +static void on_get_directory_unseen_read_line(GObject *source_object, + GAsyncResult *result, + gpointer user_data) { + get_directory_unseen_data_t *data = user_data; + + gchar *line = + g_data_input_stream_read_line_finish(data->stream, result, NULL, NULL); + + if (!line) { + data->cb(data->directory->str, data->unseen, data->user_data); + free_get_directory_unseen_data(data); + return; + } + + data->unseen += 1; + g_free(line); + + g_data_input_stream_read_line_async( + data->stream, 0, NULL, on_get_directory_unseen_read_line, data); +} + + +static void on_get_messages_read_line(GObject *source_object, + GAsyncResult *result, + gpointer user_data) { + get_messages_data_t *data = user_data; + + gchar *line = + g_data_input_stream_read_line_finish(data->stream, result, NULL, NULL); + + if (!line) { + data->messages = reverse_messages(data->messages); + data->cb(data->directory->str, data->messages, data->user_data); + free_get_messages_data(data); + return; + } + + data->line_buff[data->line_buff_count++] = line; + + if (data->line_buff_count >= 6) { + gsize depth = get_message_depth(data->line_buff[0]); + data->messages = + add_message(data->messages, depth, data->line_buff + 1); + + for (gsize i = 0; i < data->line_buff_count; ++i) + g_free(data->line_buff[i]); + data->line_buff_count = 0; + } + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_messages_read_line, data); +} + + +static void on_get_message_read_all(GObject *source_object, + GAsyncResult *result, gpointer user_data) { + get_message_data_t *data = user_data; + GInputStream *stream = g_subprocess_get_stdout_pipe(data->process); + + gsize count = 0; + g_input_stream_read_all_finish(stream, result, &count, NULL); + g_string_append_len(data->message, data->buff, count); + + if (count < sizeof(data->buff)) { + data->cb(data->path->str, data->message->str, data->user_data); + free_get_message_data(data); + return; + } + + g_input_stream_read_all_async(stream, data->buff, sizeof(data->buff), 0, + NULL, on_get_message_read_all, data); +} + + +void mbgui_get_directories(gchar **argv, mbgui_get_directories_cb_t cb, + gpointer user_data) { + GStrvBuilder *new_argv_builder = g_strv_builder_new(); + g_strv_builder_add_many(new_argv_builder, "mdirs", "-a", NULL); + g_strv_builder_addv(new_argv_builder, (const gchar **)argv); + + gchar **new_argv = g_strv_builder_end(new_argv_builder); + g_strv_builder_unref(new_argv_builder); + + get_directories_data_t *data = g_malloc(sizeof(get_directories_data_t)); + data->cb = cb; + data->user_data = user_data; + data->directories = NULL; + data->process = g_subprocess_newv((const gchar **)new_argv, + G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL); + data->stream = + g_data_input_stream_new(g_subprocess_get_stdout_pipe(data->process)); + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_directories_read_line, data); + + g_strfreev(new_argv); +} + + +void mbgui_get_directory_total(gchar *directory, + mbgui_get_directory_total_cb_t cb, + gpointer user_data) { + get_directory_total_data_t *data = + g_malloc(sizeof(get_directory_total_data_t)); + data->directory = g_string_new(directory); + data->cb = cb; + data->user_data = user_data; + data->total = 0; + data->process = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL, + "mlist", directory, NULL); + data->stream = + g_data_input_stream_new(g_subprocess_get_stdout_pipe(data->process)); + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_directory_total_read_line, data); +} + + +void mbgui_get_directory_unseen(gchar *directory, + mbgui_get_directory_unseen_cb_t cb, + gpointer user_data) { + get_directory_unseen_data_t *data = + g_malloc(sizeof(get_directory_unseen_data_t)); + data->directory = g_string_new(directory); + data->cb = cb; + data->user_data = user_data; + data->unseen = 0; + data->process = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL, + "mlist", "-s", directory, NULL); + data->stream = + g_data_input_stream_new(g_subprocess_get_stdout_pipe(data->process)); + + g_data_input_stream_read_line_async( + data->stream, 0, NULL, on_get_directory_unseen_read_line, data); +} + + +void mbgui_get_messages(gchar *directory, mbgui_get_messages_cb_t cb, + gpointer user_data) { + get_messages_data_t *data = g_malloc(sizeof(get_messages_data_t)); + data->directory = g_string_new(directory), data->cb = cb; + data->user_data = user_data; + data->messages = NULL; + data->line_buff_count = 0; + data->mlist_stdout_fd = -1; + data->mthread_stdout_fd = -1; + data->mscan_stdout_fd = -1; + data->mscan_stdout = NULL; + data->stream = NULL; + + const gchar *mlist_argv[] = {"mlist", directory, NULL}; + if (!g_spawn_async_with_pipes_and_fds( + NULL, mlist_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, -1, -1, -1, + NULL, NULL, 0, NULL, NULL, &(data->mlist_stdout_fd), NULL, NULL)) { + g_printerr(">> mlist err"); + free_get_messages_data(data); + return; + } + + const gchar *mthread_argv[] = {"mthread", "-r", NULL}; + if (!g_spawn_async_with_pipes_and_fds( + NULL, mthread_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, + data->mlist_stdout_fd, -1, -1, NULL, NULL, 0, NULL, NULL, + &(data->mthread_stdout_fd), NULL, NULL)) { + g_printerr(">> mthread err"); + free_get_messages_data(data); + return; + } + + const gchar *mscan_argv[] = {"mscan", "-f", "%i\n%R\n%u\n%s\n%f\n%D", NULL}; + if (!g_spawn_async_with_pipes_and_fds( + NULL, mscan_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, + data->mthread_stdout_fd, -1, -1, NULL, NULL, 0, NULL, NULL, + &(data->mscan_stdout_fd), NULL, NULL)) { + g_printerr(">> mscan err"); + free_get_messages_data(data); + return; + } + + data->mscan_stdout = g_unix_input_stream_new(data->mscan_stdout_fd, FALSE); + data->stream = g_data_input_stream_new(data->mscan_stdout); + + g_data_input_stream_read_line_async(data->stream, 0, NULL, + on_get_messages_read_line, data); +} + + +void mbgui_get_message(gchar *path, mbgui_get_message_cb_t cb, + gpointer user_data) { + get_message_data_t *data = g_malloc(sizeof(get_message_data_t)); + data->path = g_string_new(path); + data->cb = cb; + data->user_data = user_data; + data->message = g_string_new(""); + data->process = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL, + "mshow", path, NULL); + + GInputStream *stream = g_subprocess_get_stdout_pipe(data->process); + g_input_stream_read_all_async(stream, data->buff, sizeof(data->buff), 0, + NULL, on_get_message_read_all, data); +} diff --git a/src_c/mblaze.h b/src_c/mblaze.h new file mode 100644 index 0000000..e49abc5 --- /dev/null +++ b/src_c/mblaze.h @@ -0,0 +1,59 @@ +#ifndef MBGUI_MBLAZE_H +#define MBGUI_MBLAZE_H + +#include + + +typedef enum { + MBGUI_MSG_STATUS_SEEN = ' ', + MBGUI_MSG_STATUS_FLAGGED = '*', + MBGUI_MSG_STATUS_UNSEEN = '.', + MBGUI_MSG_STATUS_TRASHED = 'x', + MBGUI_MSG_STATUS_VIRTUAL = 'v' +} mbgui_message_status_t; + +typedef struct mbgui_directory_t { + GString *path; + GString *name; + struct mbgui_directory_t *children; + struct mbgui_directory_t *next; +} mbgui_directory_t; + +typedef struct mbgui_message_t { + GString *path; + mbgui_message_status_t status; + GString *subject; + GString *sender; + GString *date; + struct mbgui_message_t *children; + struct mbgui_message_t *next; +} mbgui_message_t; + + +typedef void (*mbgui_get_directories_cb_t)(mbgui_directory_t *directories, + gpointer user_data); +typedef void (*mbgui_get_directory_total_cb_t)(gchar *directory, gsize total, + gpointer user_data); +typedef void (*mbgui_get_directory_unseen_cb_t)(gchar *directory, gsize unseen, + gpointer user_data); +typedef void (*mbgui_get_messages_cb_t)(gchar *directory, + mbgui_message_t *messages, + gpointer user_data); +typedef void (*mbgui_get_message_cb_t)(gchar *path, gchar *message, + gpointer user_data); + + +void mbgui_get_directories(gchar **argv, mbgui_get_directories_cb_t cb, + gpointer user_data); +void mbgui_get_directory_total(gchar *directory, + mbgui_get_directory_total_cb_t cb, + gpointer user_data); +void mbgui_get_directory_unseen(gchar *directory, + mbgui_get_directory_unseen_cb_t cb, + gpointer user_data); +void mbgui_get_messages(gchar *directory, mbgui_get_messages_cb_t cb, + gpointer user_data); +void mbgui_get_message(gchar *path, mbgui_get_message_cb_t cb, + gpointer user_data); + +#endif -- cgit v1.2.3-70-g09d2