1 /* $Id$ */
2 /* Copyright (c) 2008-2015 Pierre Pronchery <khorben@defora.org> */
3 /* This file is part of DeforaOS Desktop Browser */
4 /* Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the authors nor the names of the contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29
30
31
32 #include <stdio.h>
33 #include <libintl.h>
34
35
36 /* macros */
37 #ifndef _
38 # define _(string) gettext(string)
39 #endif
40 #define min(a, b) ((a) < (b)) ? (a) : (b)
41
42
43 /* prototypes */
44 #ifdef COMMON_CONFIG_FILENAME
45 static String * _common_config_filename(String const * name);
46 #endif
47
48 #ifdef COMMON_DND
49 static int _common_drag_data_received(GdkDragContext * context,
50 GtkSelectionData * seldata, char const * dest);
51 #endif
52
53 #ifdef COMMON_EXEC
54 static int _common_exec(char const * program, char const * flags, GList * args);
55 #endif
56
57 #ifdef COMMON_GET_ABSOLUTE_PATH
58 static char * _common_get_absolute_path(char const * path);
59 #endif
60
61 #ifdef COMMON_SIZE
62 static char const * _common_size(off_t size);
63 #endif
64
65 #ifdef COMMON_SYMLINK
66 static int _common_symlink(GtkWidget * window, char const * cur);
67 #endif
68
69
70 /* functions */
71 #ifdef COMMON_CONFIG_FILENAME
_common_config_filename(String const * name)72 static String * _common_config_filename(String const * name)
73 {
74 char const * homedir;
75
76 if((homedir = getenv("HOME")) == NULL)
77 homedir = g_get_home_dir();
78 return string_new_append(homedir, "/", name, NULL);
79 }
80 #endif
81
82
83 #ifdef COMMON_DND
84 /* common_drag_data_received */
_common_drag_data_received(GdkDragContext * context,GtkSelectionData * seldata,char const * dest)85 static int _common_drag_data_received(GdkDragContext * context,
86 GtkSelectionData * seldata, char const * dest)
87 {
88 int ret = 0;
89 size_t len;
90 size_t i;
91 GList * selection = NULL;
92 char * p;
93 GdkDragAction action;
94 #ifdef DEBUG
95 GList * s;
96 #endif
97
98 #if GTK_CHECK_VERSION(2, 14, 0)
99 if(gtk_selection_data_get_length(seldata) <= 0
100 || gtk_selection_data_get_data(seldata) == NULL)
101 return 0;
102 len = gtk_selection_data_get_length(seldata);
103 #else
104 if(seldata->length <= 0 || seldata->data == NULL)
105 return 0;
106 len = seldata->length;
107 #endif
108 for(i = 0; i < len; i += strlen(p) + 1)
109 {
110 #if GTK_CHECK_VERSION(2, 14, 0)
111 p = (char *)gtk_selection_data_get_data(seldata);
112 p = &p[i];
113 #else
114 p = (char *)&seldata->data[i];
115 #endif
116 selection = g_list_append(selection, p);
117 }
118 #if GTK_CHECK_VERSION(2, 22, 0)
119 action = gdk_drag_context_get_suggested_action(context);
120 #else
121 action = context->suggested_action;
122 #endif
123 #ifdef DEBUG
124 fprintf(stderr, "%s%s%s%s%s", "DEBUG: ", action == GDK_ACTION_COPY
125 ? _("copying") : _("moving"), _(" to \""), dest,
126 "\":\n");
127 for(s = selection; s != NULL; s = s->next)
128 fprintf(stderr, "DEBUG: \"%s\"\n", (char const *)s->data);
129 #else
130 selection = g_list_append(selection, (char *)dest); /* XXX */
131 if(action == GDK_ACTION_COPY)
132 ret = _common_exec("copy", "-iR", selection);
133 else if(action == GDK_ACTION_MOVE)
134 ret = _common_exec("move", "-i", selection);
135 #endif
136 g_list_free(selection);
137 return ret;
138 }
139 #endif /* COMMON_DND */
140
141
142 #ifdef COMMON_EXEC
143 /* common_exec */
_common_exec(char const * program,char const * flags,GList * args)144 static int _common_exec(char const * program, char const * flags, GList * args)
145 {
146 int ret = 0;
147 unsigned long i = (flags != NULL) ? 3 : 2;
148 char ** argv = NULL;
149 GList * a;
150 char ** p;
151 GError * error = NULL;
152
153 if(args == NULL)
154 return 0;
155 for(a = args; a != NULL; a = a->next)
156 {
157 if(a->data == NULL)
158 continue;
159 if((p = realloc(argv, sizeof(*argv) * (i + 2))) == NULL)
160 break;
161 argv = p;
162 argv[i++] = a->data;
163 }
164 if(a != NULL)
165 {
166 free(argv);
167 return -error_set_code(1, "%s: %s", program, strerror(errno));
168 }
169 if(argv == NULL)
170 return 0;
171 #ifdef DEBUG
172 argv[0] = strdup("echo");
173 #else
174 argv[0] = strdup(program);
175 #endif
176 if(argv[0] == NULL)
177 {
178 free(argv);
179 return -error_set_code(1, "%s: %s", program, strerror(errno));
180 }
181 argv[i] = NULL;
182 i = 0;
183 if(flags != NULL)
184 argv[++i] = strdup(flags); /* XXX may fail too */
185 argv[i + 1] = "--";
186 if(g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
187 NULL, &error) != TRUE)
188 {
189 ret = error_set_code(1, "%s", error->message);
190 g_error_free(error);
191 }
192 free(argv[0]);
193 if(flags != NULL)
194 free(argv[i]);
195 return ret;
196 }
197 #endif /* COMMON_EXEC */
198
199
200 #ifdef COMMON_GET_ABSOLUTE_PATH
201 /* common_get_absolute_path */
_common_get_absolute_path(char const * path)202 static char * _common_get_absolute_path(char const * path)
203 {
204 char * p;
205 char * cur;
206 size_t i;
207
208 if(path == NULL)
209 return NULL;
210 if(g_path_is_absolute(path))
211 {
212 if((p = strdup(path)) == NULL)
213 return NULL;
214 }
215 else
216 {
217 cur = g_get_current_dir();
218 p = g_build_filename(cur, path, NULL);
219 g_free(cur);
220 }
221 /* replace "/./" by "/" */
222 for(i = strlen(p); (cur = strstr(p, "/./")) != NULL; i = strlen(p))
223 memmove(cur, &cur[2], (p + i) - (cur + 1));
224 /* replace "//" by "/" */
225 for(i = strlen(p); (cur = strstr(p, "//")) != NULL; i = strlen(p))
226 memmove(cur, &cur[1], (p + i) - (cur));
227 /* remove single dots at the end of the address */
228 i = strlen(p);
229 if(i >= 2 && strcmp(&p[i - 2], "/.") == 0)
230 p[i - 1] = '\0';
231 /* trim slashes in the end if relevant */
232 if(string_compare(p, "/") != 0)
233 string_rtrim(p, "/");
234 #ifdef DEBUG
235 fprintf(stderr, "DEBUG: %s(\"%s\") => \"%s\"\n", __func__, path, p);
236 #endif
237 return p;
238 }
239 #endif /* COMMON_GET_ABSOLUTE_PATH */
240
241
242 #ifdef COMMON_SIZE
243 /* common_size */
_common_size(off_t size)244 static char const * _common_size(off_t size)
245 {
246 static char buf[16];
247 double sz = size;
248 char * unit;
249
250 if(sz < 1024)
251 {
252 snprintf(buf, sizeof(buf), "%.0f %s", sz, _("bytes"));
253 return buf;
254 }
255 else if((sz /= 1024) < 1024)
256 unit = N_("kB");
257 else if((sz /= 1024) < 1024)
258 unit = N_("MB");
259 else if((sz /= 1024) < 1024)
260 unit = N_("GB");
261 else
262 {
263 sz /= 1024;
264 unit = N_("TB");
265 }
266 snprintf(buf, sizeof(buf), "%.1f %s", sz, _(unit));
267 return buf;
268 }
269 #endif
270
271
272 #ifdef COMMON_SYMLINK
273 /* common_symlink */
_common_symlink(GtkWidget * window,char const * cur)274 static int _common_symlink(GtkWidget * window, char const * cur)
275 {
276 static char const * newsymlink = NULL;
277 int ret = 0;
278 size_t len;
279 char * path;
280 GtkWidget * dialog;
281 GtkWidget * hbox;
282 GtkWidget * widget;
283 char const * to = NULL;
284
285 if(newsymlink == NULL)
286 newsymlink = _("New symbolic link");
287 len = strlen(cur) + strlen(newsymlink) + 2;
288 if((path = malloc(len)) == NULL)
289 return 1;
290 snprintf(path, len, "%s/%s", cur, newsymlink);
291 dialog = gtk_dialog_new_with_buttons(newsymlink,
292 (window != NULL) ? GTK_WINDOW(window) : NULL,
293 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
294 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
295 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
296 if(window == NULL)
297 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
298 #if GTK_CHECK_VERSION(3, 0, 0)
299 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
300 #else
301 hbox = gtk_hbox_new(FALSE, 0);
302 #endif
303 widget = gtk_label_new(_("Destination:"));
304 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 4);
305 widget = gtk_entry_new();
306 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 4);
307 gtk_widget_show_all(hbox);
308 #if GTK_CHECK_VERSION(2, 14, 0)
309 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(
310 dialog))), hbox, TRUE, TRUE, 4);
311 #else
312 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE,
313 4);
314 #endif
315 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
316 to = gtk_entry_get_text(GTK_ENTRY(widget));
317 if(to != NULL && strlen(to) > 0 && symlink(to, path) != 0)
318 ret = 1;
319 gtk_widget_destroy(dialog);
320 free(path);
321 return ret;
322 }
323 #endif /* COMMON_SYMLINK */
324