/* compose_attach */ int compose_attach(Compose * compose, char const * filename) { const int iconsize = 48; GtkIconTheme * theme; char const * type; GdkPixbuf * pixbuf; GtkTreeIter iter; char * p; FILE * fp; if(filename == NULL) return compose_attach_dialog(compose); if((fp = fopen(filename, "rb")) == NULL) return -compose_error(compose, strerror(errno), 1); if((p = strdup(filename)) == NULL) { fclose(fp); return -compose_error(compose, strerror(errno), 1); } compose_set_modified(compose, TRUE); theme = gtk_icon_theme_get_default(); pixbuf = NULL; if((type = mime_type(compose->mime, filename)) != NULL) mime_icons(compose->mime, type, iconsize, &pixbuf, -1); if(pixbuf == NULL) pixbuf = gtk_icon_theme_load_icon(theme, GTK_STOCK_FILE, iconsize, 0, NULL); gtk_list_store_append(compose->a_store, &iter); gtk_list_store_set(compose->a_store, &iter, CAC_FILENAME, filename, CAC_BASENAME, basename(p), CAC_ICON, pixbuf, CAC_FILE_POINTER, fp, -1); g_object_unref(pixbuf); free(p); return 0; }
/* compose_insert_file */ int compose_insert_file(Compose * compose, char const * filename) { int ret = 0; FILE * fp; GtkTextBuffer * tbuf; char buf[BUFSIZ]; size_t len; char * p; size_t rlen; size_t wlen; GError * error = NULL; if(filename == NULL) return compose_insert_file_dialog(compose); /* FIXME use a GIOChannel instead (with a GtkDialog or GtkStatusBar) */ if((fp = fopen(filename, "r")) == NULL) { snprintf(buf, sizeof(buf), "%s: %s", filename, strerror(errno)); return -compose_error(compose, buf, 1); } tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->view)); while((len = fread(buf, sizeof(char), sizeof(buf), fp)) > 0) { #if 0 if((p = g_convert(buf, len, "UTF-8", "ISO-8859-15", &rlen, &wlen, NULL)) != NULL) { gtk_text_buffer_insert_at_cursor(tbuf, p, wlen); g_free(p); } else gtk_text_buffer_insert(tbuf, &iter, buf, len); #else if((p = g_locale_to_utf8(buf, len, &rlen, &wlen, &error)) != NULL) /* FIXME may lose characters */ gtk_text_buffer_insert_at_cursor(tbuf, p, wlen); else { compose_error(compose, error->message, 1); g_error_free(error); error = NULL; gtk_text_buffer_insert_at_cursor(tbuf, buf, len); } #endif } if(ferror(fp)) { snprintf(buf, sizeof(buf), "%s: %s", filename, strerror(errno)); ret = -compose_error(compose, buf, 1); } fclose(fp); compose_set_modified(compose, TRUE); return ret; }
void compose_send(Compose * compose) { /* FIXME rewrite more efficiently (and tracking process) */ char * msg; size_t msg_len; char * body; size_t body_len; char * p; if((msg = _send_headers(compose)) == NULL) return; if((body = _send_body(compose->view)) == NULL) { free(msg); return; } msg_len = strlen(msg); body_len = strlen(body); if((p = realloc(msg, msg_len + body_len + 8)) == NULL) compose_error(compose, strerror(errno), 0); else { msg = p; snprintf(&msg[msg_len], body_len + 8, "\r\n%s\r\n.\r\n", body); msg_len += body_len + 7; _send_mail(compose, msg, msg_len); } g_free(body); }
static gboolean _on_send_write(GIOChannel * source, GIOCondition condition, gpointer data) { Compose * compose = data; gsize i; if(condition != G_IO_OUT) return FALSE; if((i = (compose->buf_len - compose->buf_pos) % 512) == 0) i = 512; if(g_io_channel_write_chars(source, &compose->buf[compose->buf_pos], i, &i, NULL) != G_IO_STATUS_NORMAL) { compose_error(compose, strerror(errno), FALSE); compose_send_cancel(compose); return FALSE; } compose->buf_pos += i; gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(compose->snd_progress), compose->buf_pos / compose->buf_len); if(compose->buf_pos >= compose->buf_len) { compose_send_cancel(compose); _compose_delete(compose); return FALSE; } return TRUE; }
static int _send_mail(Compose * compose, char * msg, size_t msg_len) { int fd[2]; GtkWidget * hbox; GtkWidget * widget; if(pipe(fd) != 0 || (compose->pid = fork()) == -1) return compose_error(compose, strerror(errno), 1); if(compose->pid == 0) return _mail_child(compose, fd); if(close(fd[0]) != 0 || fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1) compose_error(compose, strerror(errno), 0); compose->snd_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(compose->snd_window), _("Sending mail...")); gtk_window_set_resizable(GTK_WINDOW(compose->snd_window), FALSE); gtk_window_set_transient_for(GTK_WINDOW(compose->snd_window), GTK_WINDOW(compose->window)); g_signal_connect_swapped(G_OBJECT(compose->snd_window), "delete-event", G_CALLBACK(_on_send_closex), compose); #if GTK_CHECK_VERSION(3, 0, 0) hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else hbox = gtk_hbox_new(FALSE, 0); #endif gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Progress: ")), FALSE, FALSE, 0); compose->snd_progress = gtk_progress_bar_new(); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(compose->snd_progress), 0.0); gtk_box_pack_start(GTK_BOX(hbox), compose->snd_progress, TRUE, TRUE, 0); widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( compose_send_cancel), compose); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(compose->snd_window), 4); gtk_container_add(GTK_CONTAINER(compose->snd_window), hbox); gtk_widget_show_all(compose->snd_window); compose->fd = fd[1]; compose->buf = msg; compose->buf_len = msg_len; compose->buf_pos = 0; compose->channel = g_io_channel_unix_new(fd[1]); g_io_add_watch(compose->channel, G_IO_OUT, _on_send_write, compose); return 0; }
static char * _send_headers(Compose * compose) { /* FIXME rewrite this function */ char * msg = NULL; size_t msg_len = 0; char * p; GtkTreeModel * model = GTK_TREE_MODEL(compose->h_store); GtkTreeIter iter; gboolean valid; char * field; size_t field_len; char * value; char const * q; #if GTK_CHECK_VERSION(2, 24, 0) p = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT( compose->from)); #else p = gtk_combo_box_get_active_text(GTK_COMBO_BOX(compose->from)); #endif if(*p != '\0') { msg_len = strlen(p) + 8; if((msg = malloc(msg_len + 1)) == NULL) return NULL; snprintf(msg, msg_len + 1, "%s%s\r\n", "From: ", p); } g_free(p); valid = gtk_tree_model_get_iter_first(model, &iter); for(; valid == TRUE; valid = gtk_tree_model_iter_next(model, &iter)) { gtk_tree_model_get(model, &iter, 0, &field, 1, &value, -1); if(field == NULL || value == NULL || (field_len = strlen(field)) == 0 || field[field_len - 1] != ':' || index(field, ':') != field + field_len - 1) { g_free(field); g_free(value); continue; /* XXX report error */ } if((p = realloc(msg, msg_len + strlen(field) + strlen(value) + 4)) == NULL) { g_free(field); g_free(value); continue; /* XXX report error */ } msg = p; strcat(msg, field); strcat(msg, " "); strcat(msg, value); strcat(msg, "\r\n"); msg_len = strlen(msg); /* XXX ugly */ g_free(field); g_free(value); } q = gtk_entry_get_text(GTK_ENTRY(compose->subject)); msg_len += strlen(q) + 11; if((p = realloc(msg, msg_len + 1)) == NULL) return NULL; msg = p; strcat(msg, "Subject: "); strcat(msg, q); strcat(msg, "\r\n"); if(msg != NULL) return msg; if((msg = strdup("")) == NULL) compose_error(compose, strerror(errno), 0); return msg; }
Compose * compose_new(Config * config) { Compose * compose; GtkAccelGroup * group; GtkWidget * vbox; GtkWidget * toolbar; GtkToolItem * toolitem; GtkSizeGroup * sizegroup; GtkWidget * vpaned; GtkWidget * vbox2; GtkWidget * widget; GtkCellRenderer * renderer; GtkTreeViewColumn * column; GtkTreeIter iter; char const * headers[] = { "To:", "Cc:", "Bcc:", "Reply-To:", "Newsgroup:", "Followup-To:" }; size_t i; if((compose = malloc(sizeof(*compose))) == NULL) { compose_error(NULL, strerror(errno), 0); return NULL; } compose->mime = mime_new(NULL); /* check errors */ if(compose->mime == NULL) { free(compose); return NULL; } compose->config = config; compose->standalone = FALSE; /* window */ group = gtk_accel_group_new(); compose->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_add_accel_group(GTK_WINDOW(compose->window), group); #ifndef EMBEDDED gtk_window_set_default_size(GTK_WINDOW(compose->window), 512, 384); #else gtk_window_set_default_size(GTK_WINDOW(compose->window), 200, 300); #endif gtk_window_set_title(GTK_WINDOW(compose->window), _("Compose")); #if GTK_CHECK_VERSION(2, 6, 0) gtk_window_set_icon_name(GTK_WINDOW(compose->window), "mailer"); #endif g_signal_connect_swapped(G_OBJECT(compose->window), "delete-event", G_CALLBACK(_compose_on_closex), compose); vbox = gtk_vbox_new(FALSE, 0); /* menubar */ #ifndef EMBEDDED widget = desktop_menubar_create(_compose_menubar, compose, group); gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0); #endif /* toolbar */ toolbar = desktop_toolbar_create(_compose_toolbar, compose, group); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, TRUE, 0); /* from */ sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); toolbar = gtk_toolbar_new(); widget = gtk_label_new(_("From: ")); gtk_misc_set_alignment(GTK_MISC(widget), 0.1, 0.5); gtk_widget_set_size_request(widget, 80, -1); gtk_size_group_add_widget(sizegroup, widget); toolitem = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(toolitem), widget); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); #if GTK_CHECK_VERSION(2, 24, 0) compose->from = gtk_combo_box_text_new_with_entry(); #else compose->from = gtk_combo_box_entry_new_text(); #endif toolitem = gtk_tool_item_new(); gtk_tool_item_set_expand(toolitem, TRUE); gtk_container_add(GTK_CONTAINER(toolitem), compose->from); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); /* paned */ vpaned = gtk_vpaned_new(); /* headers */ widget = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); compose->h_store = gtk_list_store_new(CHC_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); compose->h_store_filter = gtk_tree_model_filter_new(GTK_TREE_MODEL( compose->h_store), NULL); gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER( compose->h_store_filter), _compose_on_headers_filter, compose, NULL); compose->h_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL( compose->h_store_filter)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(compose->h_view), FALSE); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(compose->h_view), TRUE); compose->h_headers = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); for(i = 0; i < sizeof(headers) / sizeof(*headers); i++) { gtk_list_store_append(compose->h_headers, &iter); gtk_list_store_set(compose->h_headers, &iter, 0, headers[i], 1, headers[i], -1); } renderer = gtk_cell_renderer_combo_new(); g_object_set(renderer, "editable", TRUE, "model", compose->h_headers, "text-column", 1, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK( _on_header_field_edited), compose); column = gtk_tree_view_column_new_with_attributes("", renderer, "text", CHC_HEADER, NULL); gtk_tree_view_column_set_min_width(column, 80); gtk_tree_view_append_column(GTK_TREE_VIEW(compose->h_view), column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK( _on_header_edited), compose); column = gtk_tree_view_column_new_with_attributes("", renderer, "text", CHC_VALUE, NULL); #if GTK_CHECK_VERSION(2, 4, 0) gtk_tree_view_column_set_expand(column, TRUE); #endif gtk_tree_view_append_column(GTK_TREE_VIEW(compose->h_view), column); /* default to 8-bits transfers with UTF-8 encoding */ compose_set_header(compose, "Content-Transfer-Encoding:", "8bit", FALSE); compose_set_header(compose, "Content-Type:", "text/plain; charset=UTF-8", FALSE); compose_add_field(compose, "To:", NULL); gtk_container_add(GTK_CONTAINER(widget), compose->h_view); gtk_paned_add1(GTK_PANED(vpaned), widget); /* paned */ vbox2 = gtk_vbox_new(FALSE, 0); /* subject */ toolbar = gtk_toolbar_new(); widget = gtk_label_new(_("Subject: ")); gtk_misc_set_alignment(GTK_MISC(widget), 0.1, 0.5); gtk_size_group_add_widget(sizegroup, widget); toolitem = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(toolitem), widget); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); compose->subject = gtk_entry_new(); toolitem = gtk_tool_item_new(); gtk_tool_item_set_expand(toolitem, TRUE); gtk_container_add(GTK_CONTAINER(toolitem), compose->subject); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); gtk_box_pack_start(GTK_BOX(vbox2), toolbar, FALSE, TRUE, 0); /* view */ widget = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); compose->view = _new_text_view(compose); compose_set_font(compose, _compose_get_font(compose)); gtk_container_add(GTK_CONTAINER(widget), compose->view); gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0); gtk_paned_add2(GTK_PANED(vpaned), vbox2); gtk_box_pack_start(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0); /* attachments */ compose->a_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(compose->a_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); compose->a_store = gtk_list_store_new(CAC_COUNT, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF); compose->a_view = gtk_icon_view_new_with_model(GTK_TREE_MODEL( compose->a_store)); gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(compose->a_view), CAC_ICON); gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(compose->a_view), GTK_SELECTION_MULTIPLE); gtk_icon_view_set_text_column(GTK_ICON_VIEW(compose->a_view), CAC_BASENAME); gtk_container_add(GTK_CONTAINER(compose->a_window), compose->a_view); gtk_widget_show_all(compose->a_view); gtk_widget_set_no_show_all(compose->a_window, TRUE); gtk_box_pack_start(GTK_BOX(vbox), compose->a_window, FALSE, TRUE, 0); /* statusbar */ compose->statusbar = gtk_statusbar_new(); compose->statusbar_id = 0; gtk_box_pack_start(GTK_BOX(vbox), compose->statusbar, FALSE, TRUE, 0); gtk_container_add(GTK_CONTAINER(compose->window), vbox); /* about dialog */ compose->ab_window = NULL; /* signature */ compose_append_signature(compose); compose_set_modified(compose, FALSE); compose_scroll_to_offset(compose, 0); /* display */ gtk_widget_grab_focus(compose->view); gtk_widget_show_all(vbox); gtk_widget_show(compose->window); return compose; }