Contents of /trunk/src/geotoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 194 - (show annotations)
Wed Nov 18 11:40:31 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 8530 byte(s)
Some geotoad work
1 /*
2 * Copyright (C) 2009 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of GPXView.
5 *
6 * GPXView is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GPXView is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "gpxview.h"
21
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <errno.h>
26
27 #define COLOR_ERR "red"
28 #define COLOR_OK "darkgreen"
29
30 #define BUFFER_SIZE 1500
31
32 typedef struct {
33 appdata_t *appdata;
34
35 char buf[BUFFER_SIZE];
36 int bused;
37
38 /** gdk input tag for async IO */
39 gint stdout_tag, stderr_tag;
40 gint stdin_fd, stdout_fd, stderr_fd;
41
42 struct log_s {
43 GtkTextBuffer *buffer;
44 GtkWidget *view;
45 } log;
46
47 } gt_context_t;
48
49 static void appendf(struct log_s *log, char *colname,
50 const char *fmt, ...) {
51 va_list args;
52 va_start( args, fmt );
53 char *buf = g_strdup_vprintf(fmt, args);
54 va_end( args );
55
56 GtkTextTag *tag = NULL;
57 if(colname)
58 tag = gtk_text_buffer_create_tag(log->buffer, NULL,
59 "foreground", colname,
60 NULL);
61
62 GtkTextIter end;
63 gtk_text_buffer_get_end_iter(log->buffer, &end);
64 if(tag)
65 gtk_text_buffer_insert_with_tags(log->buffer, &end, buf, -1, tag, NULL);
66 else
67 gtk_text_buffer_insert(log->buffer, &end, buf, -1);
68
69 g_free(buf);
70
71 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
72 &end, 0.0, FALSE, 0, 0);
73 }
74
75 /* watch child process and receive events */
76 static void child_state_cb(GPid pid, gint status, gpointer data) {
77
78 puts("child state");
79
80 if(WIFEXITED(status)) {
81 printf("child exited with return code %d\n", WEXITSTATUS(status));
82 } else
83 printf("child failed\n");
84
85 puts("gt exited");
86
87 /* Reap child if needed. */
88 waitpid (pid, NULL, WNOHANG);
89 }
90
91 static void child_input_cb(gpointer data, int fd, GdkInputCondition cond) {
92 gt_context_t *context = (gt_context_t*)data;
93
94 ssize_t bytes;
95 int errnosave=0;
96
97 if(cond != GDK_INPUT_READ) {
98 puts("fixme");
99 return;
100 }
101
102 /* append to current buffer content */
103 while( (bytes = read(fd, context->buf+context->bused,
104 sizeof(context->buf) - context->bused - 1)) > 0) {
105 context->bused += bytes;
106 context->buf[context->bused]='\0';
107
108 /* consume line by line */
109 gchar *ptr = context->buf;
110
111 /* parse as long as the buffer contains a newline */
112 while( strchr(ptr, '\n') != NULL) {
113 char *p = strchr(ptr, '\n');
114 *p = '\0';
115
116 appendf(&context->log, NULL, "%s\n", ptr);
117
118 ptr = p+1;
119 }
120
121 /* move remaining bytes down the buffer */
122 memmove(context->buf, ptr, sizeof(context->buf)-(ptr-context->buf));
123 context->bused -= ptr - context->buf;
124
125 /* check if buffer is full but doesn't contain any newline */
126 if(context->bused >= sizeof(context->buf)-1) {
127 printf("ERROR: reply buffer overflow\n");
128 context->bused = 0;
129 }
130 }
131
132 /* save errno from read */
133 errnosave=errno;
134
135 if(errnosave != EAGAIN && errnosave != 0) {
136 /* we probably hit EOF */
137 puts("removing io");
138
139 // TODO: fixme, make sure process is dead! kill it otherwise, but dont
140 // issue an disconnect(NULL) !!!!
141
142 gdk_input_remove(context->stdout_tag);
143 gdk_input_remove(context->stderr_tag);
144
145 appendf(&context->log, COLOR_OK, "GeoToad finished\n");
146
147 appendf(&context->log, COLOR_ERR, "TODO: free context!!!\n");
148 // printf("freeing context\n");
149 // g_free(context);
150 }
151 }
152
153 static void run(gt_context_t *context) {
154 /* setup context */
155 context->bused = 0;
156 context->stdout_tag = -1;
157 context->stderr_tag = -1;
158 context->stdin_fd = -1;
159 context->stderr_fd = -1;
160 context->stderr_fd = -1;
161
162 /* build list of arguments to call geotoad */
163 GPtrArray *gt_argv = g_ptr_array_new();
164 g_ptr_array_add (gt_argv, "/usr/bin/geotoad");
165 g_ptr_array_add (gt_argv, "--distanceMax=1.5");
166 g_ptr_array_add (gt_argv, "--output=gtoad.gpx");
167 g_ptr_array_add (gt_argv, "--password=winterblume");
168 g_ptr_array_add (gt_argv, "--queryType=coord");
169 g_ptr_array_add (gt_argv, "--user=Tantil");
170
171 /* check if we need to add proxy config */
172 char *proxy = NULL;
173 if(context->appdata->proxy && context->appdata->proxy->host) {
174 if(context->appdata->proxy->use_authentication &&
175 context->appdata->proxy->authentication_user &&
176 context->appdata->proxy->authentication_password)
177 proxy = g_strdup_printf("--proxy=http://%s:%s@%s:%d",
178 context->appdata->proxy->authentication_user,
179 context->appdata->proxy->authentication_password,
180 context->appdata->proxy->host,
181 context->appdata->proxy->port);
182 else
183 proxy = g_strdup_printf("--proxy=http://%s:%d",
184 context->appdata->proxy->host,
185 context->appdata->proxy->port);
186
187 appendf(&context->log, COLOR_OK, "Using proxy: %s\n", proxy);
188 g_ptr_array_add (gt_argv, proxy);
189 }
190
191
192 g_ptr_array_add (gt_argv, "N49 00.000 E008 23.000");
193 g_ptr_array_add (gt_argv, NULL);
194
195 GError *error=NULL;
196 GPid pid;
197 GSource *gt_watch;
198
199 if (!g_spawn_async_with_pipes (NULL, /* CWD */
200 (char **) gt_argv->pdata, /* argv */
201 NULL, /* envp */
202 G_SPAWN_DO_NOT_REAP_CHILD, /* flags */
203 NULL, /* child setup */
204 NULL, /* user data */
205 &pid,
206 &context->stdin_fd,
207 &context->stdout_fd,
208 &context->stderr_fd,
209 &error)) {
210 g_ptr_array_free(gt_argv, TRUE);
211 if(proxy) g_free(proxy);
212 appendf(&context->log, COLOR_ERR,
213 _("GeoToad failed to start: '%s'"), error->message);
214 g_error_free(error);
215 return;
216 }
217 g_ptr_array_free (gt_argv, TRUE);
218 if(proxy) g_free(proxy);
219
220 gt_watch = g_child_watch_source_new(pid);
221 g_source_set_callback(gt_watch, (GSourceFunc) child_state_cb, NULL, NULL);
222
223 g_source_attach(gt_watch, NULL);
224 g_source_unref(gt_watch);
225
226 /* make nonblocking */
227 if(fcntl(context->stdout_fd, F_SETFL, O_NONBLOCK) == -1)
228 perror("fcntl failed");
229
230 if(fcntl(context->stderr_fd, F_SETFL, O_NONBLOCK) == -1)
231 perror("fcntl failed");
232
233 /* use gdk to monitor read end of stdout */
234 context->stdout_tag = gdk_input_add(context->stdout_fd,
235 GDK_INPUT_READ, child_input_cb, context);
236 context->stderr_tag = gdk_input_add(context->stderr_fd,
237 GDK_INPUT_READ, child_input_cb, context);
238 }
239
240 void geotoad(appdata_t *appdata) {
241 gt_context_t *context = g_new0(gt_context_t, 1);
242 context->appdata = appdata;
243
244 printf("geoToad\n");
245
246 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("GeoToad"),
247 GTK_WINDOW(appdata->window),
248 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
249 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
250 NULL);
251
252 gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480);
253
254 #ifndef USE_PANNABLE_AREA
255 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
256 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
257 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
258 #else
259 GtkWidget *pannable_area = hildon_pannable_area_new();
260 #endif
261
262 context->log.buffer = gtk_text_buffer_new(NULL);
263
264 #ifndef USE_HILDON_TEXT_VIEW
265 context->log.view = gtk_text_view_new_with_buffer(context->log.buffer);
266 #else
267 context->log.view = hildon_text_view_new();
268 hildon_text_view_set_buffer(HILDON_TEXT_VIEW(context->log.view),
269 context->log.buffer);
270 #endif
271
272 #ifndef USE_PANNABLE_AREA
273 gtk_container_add(GTK_CONTAINER(scrolled_window), context->log.view);
274 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scrolled_window),
275 GTK_SHADOW_IN);
276
277 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
278 scrolled_window, TRUE, TRUE, 0);
279 #else
280 gtk_container_add(GTK_CONTAINER(pannable_area), context->log.view);
281 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
282 pannable_area, TRUE, TRUE, 0);
283 #endif
284
285 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
286
287 gtk_widget_show_all(dialog);
288
289 appendf(&context->log, COLOR_OK, "Running GeoToad\n");
290 run(context);
291
292 gtk_dialog_run(GTK_DIALOG(dialog));
293
294 gtk_widget_destroy(dialog);
295 }