1 /*
2 * sendmail.c
3 *
4 * Copyright 2007-2016 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
5 * Copyright 2007 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 * Copyright 2007, 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7 * Copyright 2008, 2009 Timothy Boronczyk <tboronczyk(at)gmail(dot)com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24 /* A little plugin to send a document as attachment using the preferred mail client */
25
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h" /* for the gettext domain */
29 #endif
30
31 #include <geanyplugin.h>
32 #include "mail-icon.xpm"
33 #include <glib.h>
34 #include <glib/gstdio.h>
35 #include <errno.h>
36
37 GeanyPlugin *geany_plugin;
38 GeanyData *geany_data;
39
40 PLUGIN_VERSION_CHECK(224)
41
42 PLUGIN_SET_TRANSLATABLE_INFO(
43 LOCALEDIR,
44 GETTEXT_PACKAGE,
45 _("SendMail"),
46 _("Sends the current file as attachment with your favorite mailer"),
47 VERSION,
48 "Frank Lanitz <frank@frank.uvena.de>")
49
50 /* Keybinding(s) */
51 enum
52 {
53 SENDMAIL_KB,
54 COUNT_KB
55 };
56
57 static gchar *config_file = NULL;
58 static gchar *mailer = NULL;
59 static gchar *address = NULL;
60 gboolean icon_in_toolbar = FALSE;
61 gboolean use_address_dialog = FALSE;
62 /* Needed global to remove from toolbar again */
63 GtkWidget *mailbutton = NULL;
64 static GtkWidget *main_menu_item = NULL;
65
66
67 /* Callback for sending file as attachment */
68 static void
send_as_attachment(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)69 send_as_attachment(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer gdata)
70 {
71 GeanyDocument *doc;
72 gchar *locale_filename = NULL;
73 gchar *command = NULL;
74 GError *error = NULL;
75 GString *cmd_str = NULL;
76 gchar *data;
77
78 doc = document_get_current();
79
80 if (doc->file_name == NULL)
81 {
82 dialogs_show_save_as();
83 }
84 else
85 {
86 document_save_file(doc, FALSE);
87 }
88
89 if (doc->file_name != NULL)
90 {
91 if (mailer)
92 {
93 locale_filename = utils_get_locale_from_utf8(doc->file_name);
94 cmd_str = g_string_new(mailer);
95 if ((use_address_dialog == TRUE) && (g_strrstr(mailer, "%r") != NULL))
96 {
97 GKeyFile *config = NULL;
98 gchar *config_dir = NULL;
99 gchar *input = dialogs_show_input(_("Recipient's Address"),
100 GTK_WINDOW(geany->main_widgets->window),
101 _("Enter the recipient's e-mail address:"),
102 address);
103
104 if (input)
105 {
106 config = g_key_file_new();
107 g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
108
109 g_free(address);
110 address = input;
111
112 g_key_file_set_string(config, "tools", "address", address);
113 }
114 else
115 {
116 g_string_free(cmd_str, TRUE);
117 g_free(locale_filename);
118 return;
119 }
120
121 config_dir = g_path_get_dirname(config_file);
122
123
124 if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) &&
125 utils_mkdir(config_dir, TRUE) != 0)
126 {
127 dialogs_show_msgbox(GTK_MESSAGE_ERROR,
128 _("Plugin configuration directory could not be created."));
129 }
130 else
131 {
132 /* write config to file */
133 data = g_key_file_to_data(config, NULL, NULL);
134 utils_write_file(config_file, data);
135 g_free(data);
136 }
137 g_key_file_free(config);
138 g_free(config_dir);
139 }
140
141 if (! utils_string_replace_all(cmd_str, "%f", locale_filename))
142 ui_set_statusbar(FALSE,
143 _("Filename placeholder not found. The executed command might have failed."));
144
145 if (use_address_dialog == TRUE && address != NULL)
146 {
147 if (! utils_string_replace_all(cmd_str, "%r", address))
148 ui_set_statusbar(FALSE,
149 _("Recipient address placeholder not found. The executed command might have failed."));
150 }
151 else
152 {
153 /* Removes %r if option was not activ but was included into command */
154 utils_string_replace_all(cmd_str, "%r", "");
155 }
156
157 utils_string_replace_all(cmd_str, "%b", g_path_get_basename(locale_filename));
158
159 command = g_string_free(cmd_str, FALSE);
160 g_spawn_command_line_async(command, &error);
161 if (error != NULL)
162 {
163 ui_set_statusbar(FALSE, _("Could not execute mailer. Please check your configuration."));
164 g_error_free(error);
165 }
166
167 g_free(locale_filename);
168 g_free(command);
169 }
170 else
171 {
172 ui_set_statusbar(FALSE, _("Please define a mail client first."));
173 }
174 }
175 else
176 {
177 ui_set_statusbar(FALSE, _("File has to be saved before sending."));
178 }
179 }
180
key_send_as_attachment(G_GNUC_UNUSED guint key_id)181 static void key_send_as_attachment(G_GNUC_UNUSED guint key_id)
182 {
183 send_as_attachment(NULL, NULL);
184 }
185
186 #define GEANYSENDMAIL_STOCK_MAIL "geanysendmail-mail"
187
add_stock_item(void)188 static void add_stock_item(void)
189 {
190 GtkIconSet *icon_set;
191 GtkIconFactory *factory = gtk_icon_factory_new();
192 GtkIconTheme *theme = gtk_icon_theme_get_default();
193 GtkStockItem item = { (gchar*)(GEANYSENDMAIL_STOCK_MAIL), (gchar*)(N_("Mail")), 0, 0, (gchar*)(GETTEXT_PACKAGE) };
194
195 if (gtk_icon_theme_has_icon(theme, "mail-message-new"))
196 {
197 GtkIconSource *icon_source = gtk_icon_source_new();
198 icon_set = gtk_icon_set_new();
199 gtk_icon_source_set_icon_name(icon_source, "mail-message-new");
200 gtk_icon_set_add_source(icon_set, icon_source);
201 gtk_icon_source_free(icon_source);
202 }
203 else
204 {
205 GdkPixbuf *pb = gdk_pixbuf_new_from_xpm_data(mail_icon);
206 icon_set = gtk_icon_set_new_from_pixbuf(pb);
207 g_object_unref(pb);
208 }
209 gtk_icon_factory_add(factory, item.stock_id, icon_set);
210 gtk_stock_add(&item, 1);
211 gtk_icon_factory_add_default(factory);
212
213 g_object_unref(factory);
214 gtk_icon_set_unref(icon_set);
215 }
216
217
show_icon(void)218 static void show_icon(void)
219 {
220 mailbutton = GTK_WIDGET(gtk_tool_button_new_from_stock(GEANYSENDMAIL_STOCK_MAIL));
221 plugin_add_toolbar_item(geany_plugin, GTK_TOOL_ITEM(mailbutton));
222 ui_add_document_sensitive(mailbutton);
223 #if GTK_CHECK_VERSION(2, 12, 0)
224 gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(mailbutton), _("Send by mail"));
225 #endif
226 g_signal_connect (G_OBJECT(mailbutton), "clicked", G_CALLBACK(send_as_attachment), NULL);
227 gtk_widget_show_all (mailbutton);
228 icon_in_toolbar = TRUE;
229 }
230
cleanup_icon(void)231 static void cleanup_icon(void)
232 {
233 if (mailbutton != NULL)
234 {
235 gtk_container_remove(GTK_CONTAINER (geany->main_widgets->toolbar), mailbutton);
236 }
237 icon_in_toolbar = FALSE;
238 }
239
240
241 static struct
242 {
243 GtkWidget *entry;
244 GtkWidget *checkbox_icon_to_toolbar;
245 GtkWidget *checkbox_use_addressdialog;
246 }
247 pref_widgets;
248
249
250 static void
on_configure_response(G_GNUC_UNUSED GtkDialog * dialog,gint response,G_GNUC_UNUSED gpointer user_data)251 on_configure_response(G_GNUC_UNUSED GtkDialog *dialog, gint response, G_GNUC_UNUSED gpointer user_data)
252 {
253 if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
254 {
255 GKeyFile *config = g_key_file_new();
256 gchar *config_dir = g_path_get_dirname(config_file);
257 gboolean configure_toogle_status;
258
259 g_free(mailer);
260 mailer = g_strdup(gtk_entry_get_text(GTK_ENTRY(pref_widgets.entry)));
261
262 configure_toogle_status =
263 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.checkbox_icon_to_toolbar));
264
265 if (icon_in_toolbar ^ configure_toogle_status)
266 /* Only do anything if a status change is needed */
267 {
268 if (icon_in_toolbar == TRUE)
269 {
270 /* We need to remove the toolbar icon */
271 cleanup_icon();
272 }
273 else
274 {
275 /* We need to show the toolbar icon */
276 show_icon();
277 }
278 }
279
280 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.checkbox_use_addressdialog)) == TRUE)
281 use_address_dialog = TRUE;
282 else
283 use_address_dialog = FALSE;
284
285 g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
286 g_key_file_set_string(config, "tools", "mailer", mailer);
287 g_key_file_set_boolean(config, "tools", "address_usage", use_address_dialog);
288 g_key_file_set_boolean(config, "icon", "show_icon", icon_in_toolbar);
289
290 if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
291 {
292 dialogs_show_msgbox(GTK_MESSAGE_ERROR,
293 _("Plugin configuration directory could not be created."));
294 }
295 else
296 {
297 /* write config to file */
298 gchar *data = g_key_file_to_data(config, NULL, NULL);
299 utils_write_file(config_file, data);
300 g_free(data);
301 }
302 g_key_file_free(config);
303 g_free(config_dir);
304 }
305 }
306
plugin_configure(GtkDialog * dialog)307 GtkWidget *plugin_configure(GtkDialog *dialog)
308 {
309 GtkWidget *label1, *label2, *vbox;
310
311 vbox = gtk_vbox_new(FALSE, 6);
312
313 /* add a label and a text entry to the dialog */
314 label1 = gtk_label_new(_("Path and options for the mail client:"));
315 gtk_widget_show(label1);
316 gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
317 pref_widgets.entry = gtk_entry_new();
318 gtk_widget_show(pref_widgets.entry);
319 if (mailer != NULL)
320 gtk_entry_set_text(GTK_ENTRY(pref_widgets.entry), mailer);
321
322 label2 = gtk_label_new(_("Note: \n\t%f will be replaced by your file."\
323 "\n\t%r will be replaced by recipient's email address."\
324 "\n\t%b will be replaced by basename of a file"\
325 "\n\tExamples:"\
326 "\n\tsylpheed --attach \"%f\" --compose \"%r\""\
327 "\n\tmutt -s \"Sending \'%b\'\" -a \"%f\" \"%r\""));
328 gtk_label_set_selectable(GTK_LABEL(label2), TRUE);
329 gtk_widget_show(label2);
330 gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
331
332 pref_widgets.checkbox_icon_to_toolbar = gtk_check_button_new_with_label(_("Show toolbar icon"));
333 gtk_widget_set_tooltip_text(pref_widgets.checkbox_icon_to_toolbar,
334 _("Shows a icon in the toolbar to send file more easy."));
335 gtk_button_set_focus_on_click(GTK_BUTTON(pref_widgets.checkbox_icon_to_toolbar), FALSE);
336 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pref_widgets.checkbox_icon_to_toolbar), icon_in_toolbar);
337 gtk_widget_show(pref_widgets.checkbox_icon_to_toolbar);
338
339 pref_widgets.checkbox_use_addressdialog = gtk_check_button_new_with_label(_
340 ("Use dialog for entering email address of recipients"));
341
342 gtk_button_set_focus_on_click(GTK_BUTTON(pref_widgets.checkbox_use_addressdialog), FALSE);
343 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pref_widgets.checkbox_use_addressdialog), use_address_dialog);
344 gtk_widget_show(pref_widgets.checkbox_use_addressdialog);
345
346 gtk_box_pack_start(GTK_BOX(vbox), label1, FALSE, FALSE, 0);
347 gtk_box_pack_start(GTK_BOX(vbox), pref_widgets.entry, FALSE, FALSE, 0);
348 gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 0);
349 gtk_box_pack_start(GTK_BOX(vbox), pref_widgets.checkbox_icon_to_toolbar, FALSE, FALSE, 0);
350 gtk_box_pack_start(GTK_BOX(vbox), pref_widgets.checkbox_use_addressdialog, FALSE, FALSE, 0);
351
352 gtk_widget_show(vbox);
353
354 g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
355 return vbox;
356 }
357
358 /* Called by Geany to initialize the plugin */
plugin_init(GeanyData G_GNUC_UNUSED * data)359 void plugin_init(GeanyData G_GNUC_UNUSED *data)
360 {
361 GKeyFile *config = g_key_file_new();
362 gchar *config_file_old = NULL;
363 gchar *config_dir = NULL;
364 gchar *config_dir_old = NULL;
365 gchar *kb_label = _("Send file by mail");
366 GtkWidget *menu_mail = NULL;
367 GeanyKeyGroup *key_group;
368
369 config_file = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
370 "sendmail", G_DIR_SEPARATOR_S, "mail.conf", NULL);
371
372 #ifndef G_OS_WIN32
373 /* We try only to move if we are on not Windows platform */
374 config_file_old = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S,
375 "plugins", G_DIR_SEPARATOR_S,
376 "geanysendmail", G_DIR_SEPARATOR_S, "mail.conf", NULL);
377 config_dir = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S,
378 "plugins", G_DIR_SEPARATOR_S, "sendmail", NULL);
379 config_dir_old = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S,
380 "plugins", G_DIR_SEPARATOR_S, "geanysendmail", NULL);
381
382 if (g_file_test(config_file_old, G_FILE_TEST_EXISTS))
383 {
384 if (dialogs_show_question(
385 _("Renamed plugin detected!\n"
386 "\n"
387 "GeanySendMail has been renamed to sendmail -- you surely have "
388 "already recognised it. \n"
389 "Geany is able to migrate your old plugin configuration by "
390 "moving the old configuration file to new location.\n"
391 "Move now?")))
392 {
393 if (g_rename(config_dir_old, config_dir) == 0)
394 {
395 dialogs_show_msgbox(GTK_MESSAGE_INFO,
396 _("Your configuration directory has been "
397 "successfully moved from \"%s\" to \"%s\"."),
398 config_dir_old, config_dir);
399 }
400 else
401 {
402 /* If there was an error on migrating we need
403 * to load from original one.
404 * When saving new configuration it will go to
405 * new folder so migration should
406 * be implicit. */
407 g_free(config_file);
408 config_file = g_strdup(config_file_old);
409 dialogs_show_msgbox(
410 GTK_MESSAGE_WARNING,
411 _("Your old configuration directory \"%s\" could "
412 "not be moved to \"%s\" (%s). "
413 "Please move manually the directory to the new location."),
414 config_dir_old,
415 config_dir,
416 g_strerror(errno));
417 }
418 }
419 }
420
421 g_free(config_dir_old);
422 g_free(config_dir);
423 g_free(config_file_old);
424 #endif
425
426 /* Initialising options from config file */
427 g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
428 mailer = g_key_file_get_string(config, "tools", "mailer", NULL);
429 address = g_key_file_get_string(config, "tools", "address", NULL);
430 use_address_dialog = g_key_file_get_boolean(config, "tools", "address_usage", NULL);
431 icon_in_toolbar = g_key_file_get_boolean(config, "icon", "show_icon", NULL);
432
433 g_key_file_free(config);
434
435 add_stock_item();
436 if (icon_in_toolbar == TRUE)
437 {
438 show_icon();
439 }
440
441 /* Build up menu entry */
442 menu_mail = gtk_menu_item_new_with_mnemonic(_("_Mail document"));
443 gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), menu_mail);
444 gtk_widget_set_tooltip_text(menu_mail,
445 _("Sends the opened file as unzipped attachment by any mailer from your $PATH"));
446 g_signal_connect(G_OBJECT(menu_mail), "activate", G_CALLBACK(send_as_attachment), NULL);
447
448 /* setup keybindings */
449 key_group = plugin_set_key_group(geany_plugin, "sendmail", COUNT_KB, NULL);
450 keybindings_set_item(key_group, SENDMAIL_KB, key_send_as_attachment,
451 0, 0, "send_file_as_attachment", kb_label, menu_mail);
452
453 gtk_widget_show_all(menu_mail);
454 ui_add_document_sensitive(menu_mail);
455 main_menu_item = menu_mail;
456 }
457
458
plugin_cleanup(void)459 void plugin_cleanup(void)
460 {
461 gtk_widget_destroy(main_menu_item);
462 cleanup_icon();
463 g_free(mailer);
464 g_free(address);
465 g_free(config_file);
466 }
467