rejig downloads a bit to accomodate windows
[xombrero.git] / externaleditor.c
blob65ce4aef7c8f700f0fa0bf2f96546fa695c3381f
1 /*
2 * Copyright (c) 2012 Elias Norberg <xyzzy@kudzu.se>
3 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <xombrero.h>
20 #if !defined(XT_SIGNALS_DISABLE) && (WEBKIT_CHECK_VERSION(1, 5, 0))
21 /* we got the DOM API we need */
23 struct edit_src_cb_args {
24 WebKitWebFrame *frame;
25 WebKitWebDataSource *data_src;
28 struct open_external_editor_cb_args {
29 GPid child_pid;
30 char *path;
31 time_t mtime;
32 struct tab *tab;
33 int (*callback)(const char *,gpointer);
34 gpointer cb_data;
37 int
38 open_external_editor_cb(gpointer data)
40 struct open_external_editor_cb_args *args;
41 struct stat st;
42 struct tab *t;
44 int fd = -1;
45 int rv, nb;
46 int status;
47 int found_tab = 0;
48 GString *contents = NULL;
49 char buf[XT_EE_BUFSZ];
51 args = (struct open_external_editor_cb_args*)data;
53 /* Check if tab is still open */
54 TAILQ_FOREACH(t, &tabs, entry)
55 if (t == args->tab) {
56 found_tab = 1;
57 break;
60 /* Tab was deleted */
61 if (!found_tab){
62 g_free(args->path);
63 g_free(args->cb_data);
64 g_free(args);
65 return (0);
68 rv = stat(args->path, &st);
69 if (rv == -1 && errno != ENOENT) {
70 DPRINTF("open_external_editor_cb: stat error, file %s, "
71 "error: %s\n", args->path, strerror(errno));
72 show_oops(args->tab, "stat error : %s", strerror(errno));
73 goto done;
74 } else if ( rv == 0 && st.st_mtime > args->mtime) {
75 DPRINTF("File %s has been modified\n", args->path);
76 args->mtime = st.st_mtime;
78 contents = g_string_sized_new(XT_EE_BUFSZ);
79 fd = open(args->path, O_RDONLY);
80 if (fd == -1) {
81 DPRINTF("open_external_editor_cb, open error, %s\n",
82 strerror(errno));
83 goto done;
86 for (;;) {
87 nb = read(fd, buf, XT_EE_BUFSZ);
88 if (nb < 0) {
89 g_string_free(contents, TRUE);
90 show_oops(args->tab, strerror(errno));
91 goto done;
94 buf[nb] = '\0';
95 contents = g_string_append(contents, buf);
97 if (nb < XT_EE_BUFSZ)
98 break;
100 close(fd);
101 fd = -1;
103 DPRINTF("external_editor_cb: contents updated\n");
104 if (args->callback)
105 args->callback(contents->str, args->cb_data);
107 g_string_free(contents, TRUE);
110 /* Check if child has terminated */
111 rv = waitpid(args->child_pid, &status, WNOHANG);
112 if (rv == -1 /* || WIFEXITED(status) */) {
113 /* Delete the file */
114 unlink(args->path);
115 goto done;
118 return (1);
119 done:
120 g_spawn_close_pid(args->child_pid);
121 g_free(args->path);
122 g_free(args->cb_data);
123 g_free(args);
125 if (fd != -1)
126 close(fd);
128 return (0);
132 open_external_editor(struct tab *t, const char *contents, const char *suffix,
133 int (*callback)(const char *, gpointer), gpointer cb_data)
135 struct stat st;
136 struct open_external_editor_cb_args *a;
137 GPid pid;
138 char *cmdstr;
139 char filename[PATH_MAX];
140 char **sv;
141 int fd;
142 int nb, rv;
143 int cnt;
145 if (external_editor == NULL)
146 return (0);
148 if (suffix == NULL)
149 suffix = "";
151 snprintf(filename, sizeof filename, "%s" PS "xombreroXXXXXX%s",
152 temp_dir, suffix);
154 /* Create a temporary file */
155 fd = mkstemps(filename, strlen(suffix));
156 if (fd == -1) {
157 show_oops(t, "Cannot create temporary file");
158 return (1);
161 nb = 0;
162 while (nb < strlen(contents)) {
163 if (strlen(contents) - nb > XT_EE_BUFSZ)
164 cnt = XT_EE_BUFSZ;
165 else
166 cnt = strlen(contents) - nb;
168 rv = write(fd, contents+nb, cnt);
169 if (rv < 0) {
170 close(fd);
171 show_oops(t,strerror(errno));
172 return (1);
175 nb += rv;
178 rv = fstat(fd, &st);
179 if (rv == -1) {
180 close(fd);
181 show_oops(t,"Cannot stat file: %s\n", strerror(errno));
182 return (1);
184 close(fd);
186 DPRINTF("edit_src: external_editor: %s\n", external_editor);
188 sv = g_strsplit(external_editor, "<file>", -1);
189 cmdstr = g_strjoinv(filename, sv);
190 g_strfreev(sv);
191 sv = g_strsplit_set(cmdstr, " \t", -1);
192 if (!g_spawn_async(NULL, sv, NULL,
193 (G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), NULL, NULL, &pid,
194 NULL)) {
195 show_oops(t, "%s: could not spawn process");
196 g_strfreev(sv);
197 g_free(cmdstr);
198 return (1);
201 /* parent */
202 g_strfreev(sv);
203 g_free(cmdstr);
205 a = g_malloc(sizeof(struct open_external_editor_cb_args));
206 a->child_pid = pid;
207 a->path = g_strdup(filename);
208 a->tab = t;
209 a->mtime = st.st_mtime;
210 a->callback = callback;
211 a->cb_data = cb_data;
213 /* Check every 100 ms if file has changed */
214 g_timeout_add(100, (GSourceFunc)open_external_editor_cb,
215 (gpointer)a);
216 return (0);
220 edit_src_cb(const char *contents, gpointer data)
222 struct edit_src_cb_args *args;
224 args = (struct edit_src_cb_args *)data;
226 webkit_web_frame_load_string(args->frame, contents, NULL,
227 webkit_web_data_source_get_encoding(args->data_src),
228 webkit_web_frame_get_uri(args->frame));
229 return (0);
233 edit_src(struct tab *t, struct karg *args)
235 WebKitWebFrame *frame;
236 WebKitWebDataSource *ds;
237 GString *contents;
238 struct edit_src_cb_args *ext_args;
240 if (external_editor == NULL){
241 show_oops(t,"Setting external_editor not set");
242 return (1);
245 frame = webkit_web_view_get_focused_frame(t->wv);
246 ds = webkit_web_frame_get_data_source(frame);
247 if (webkit_web_data_source_is_loading(ds)) {
248 show_oops(t,"Webpage is still loading.");
249 return (1);
252 contents = webkit_web_data_source_get_data(ds);
253 if (!contents)
254 show_oops(t,"No contents - opening empty file");
256 ext_args = g_malloc(sizeof(struct edit_src_cb_args));
257 ext_args->frame = frame;
258 ext_args->data_src = ds;
260 /* Check every 100 ms if file has changed */
261 open_external_editor(t, contents->str, ".html", &edit_src_cb, ext_args);
262 return (0);
265 struct edit_element_cb_args {
266 WebKitDOMElement *active;
267 struct tab *tab;
271 edit_element_cb(const char *contents, gpointer data)
273 struct edit_element_cb_args *args;
274 WebKitDOMHTMLTextAreaElement *ta;
275 WebKitDOMHTMLInputElement *el;
277 args = (struct edit_element_cb_args*)data;
279 if (!args || !args->active)
280 return (0);
282 el = (WebKitDOMHTMLInputElement*)args->active;
283 ta = (WebKitDOMHTMLTextAreaElement*)args->active;
285 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
286 webkit_dom_html_input_element_set_value(el, contents);
287 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
288 webkit_dom_html_text_area_element_set_value(ta, contents);
290 return (0);
294 edit_element(struct tab *t, struct karg *a)
296 WebKitDOMHTMLDocument *doc;
297 WebKitDOMElement *active_element;
298 WebKitDOMHTMLTextAreaElement *ta;
299 WebKitDOMHTMLInputElement *el;
300 char *contents;
301 struct edit_element_cb_args *args;
303 if (external_editor == NULL){
304 show_oops(t,"Setting external_editor not set");
305 return (0);
308 doc = (WebKitDOMHTMLDocument*)webkit_web_view_get_dom_document(t->wv);
309 active_element = webkit_dom_html_document_get_active_element(doc);
310 el = (WebKitDOMHTMLInputElement*)active_element;
311 ta = (WebKitDOMHTMLTextAreaElement*)active_element;
313 if (doc == NULL || active_element == NULL ||
314 (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el) == 0 &&
315 WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta) == 0)) {
316 show_oops(t, "No active text element!");
317 return (1);
320 contents = "";
321 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
322 contents = webkit_dom_html_input_element_get_value(el);
323 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
324 contents = webkit_dom_html_text_area_element_get_value(ta);
326 if ((args = g_malloc(sizeof(struct edit_element_cb_args))) == NULL)
327 return (1);
329 args->tab = t;
330 args->active = active_element;
332 open_external_editor(t, contents, NULL, &edit_element_cb, args);
334 return (0);
337 #else /* Just to make things compile. */
340 edit_element(struct tab *t, struct karg *a)
342 show_oops(t, "external editor feature requires webkit >= 1.5.0");
343 return (1);
347 edit_src(struct tab *t, struct karg *args)
349 show_oops(t, "external editor feature requires webkit >= 1.5.0");
350 return (1);
353 #endif