1
2 /*
3 * Copyright (C) 2002-2012 Edscott Wilson Garcia
4 * EMail: edscott@users.sf.net
5 *
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program;
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "rodent.h"
27 #include "rfm_modules.h"
28
29 static GSList *bookmarks = NULL;
30 enum transport_e {
31 LOCAL_TRANSPORT,
32 NFS_TRANSPORT,
33 CIFS_TRANSPORT,
34 OBEX_TRANSPORT,
35 SSH_TRANSPORT,
36 FTP_TRANSPORT,
37 EFS_TRANSPORT
38 };
39
40 static RFM_RW_LOCK_INIT(bookmarks_lock);
41 typedef struct bookmark_item_t {
42 gchar *uri;
43 gchar *path;
44 gchar *hostname;
45 enum transport_e transport_type;
46 }bookmark_item_t;
47
48 static
get_bookmarks_filename(void)49 gchar *get_bookmarks_filename(void){
50 return g_build_filename(BOOKMARKS_FILE, NULL);
51 }
52
53 static
bookmark_item_new(void)54 bookmark_item_t *bookmark_item_new(void){
55 bookmark_item_t *bookmark_item_p = (bookmark_item_t *)malloc(sizeof(bookmark_item_t));
56 if (!bookmark_item_p) g_error("malloc: %s\n", strerror(errno));
57 memset(bookmark_item_p, 0, sizeof(bookmark_item_t));
58 return bookmark_item_p;
59 }
60
61 static
bookmark_item_free(bookmark_item_t * bookmark_item_p)62 void bookmark_item_free( bookmark_item_t *bookmark_item_p){
63 if (!bookmark_item_p) return;
64 g_free(bookmark_item_p->uri);
65 g_free(bookmark_item_p->path);
66 g_free(bookmark_item_p->hostname);
67 g_free(bookmark_item_p);
68 return;
69 }
70
71
72
73 static
74 gpointer
read_bookmark_file_f(gpointer data)75 read_bookmark_file_f(gpointer data){
76 NOOP(stderr,"now reading bookmark file\n");
77 gchar *filename = get_bookmarks_filename();
78 rfm_rw_lock_writer_lock(&bookmarks_lock);
79 FILE *f=fopen(filename, "r");
80 g_free(filename);
81 if (!f) {
82 NOOP("read_bookmark_file_f(): g_mutex_unlock\n");
83 rfm_rw_lock_writer_unlock(&bookmarks_lock);
84 return NULL;
85 }
86 GSList *tmp=bookmarks;
87 for (;tmp && tmp->data; tmp=tmp->next){
88 bookmark_item_free((bookmark_item_t *)(tmp->data));
89 }
90 g_slist_free(bookmarks);
91 bookmarks=NULL;
92
93 gchar buffer[2048];
94
95 while (fgets(buffer, 2047, f) && !feof(f)){
96 if (strchr(buffer, '\n')) *strchr(buffer, '\n')=0;
97 if (strlen(buffer)==0) continue;
98 bookmark_item_t *bookmark_item_p = bookmark_item_new();
99 bookmark_item_p->uri = g_strdup(buffer);
100 GError *error = NULL;
101 bookmark_item_p->path = g_filename_from_uri (bookmark_item_p->uri, &(bookmark_item_p->hostname), &error);
102 if (error) {
103 bookmark_item_p->path = NULL;
104 DBG("rodent_bookmarks.c %s: %s\n", bookmark_item_p->uri, error->message);
105 g_error_free(error);
106 //continue;
107 }
108 bookmarks=g_slist_prepend(bookmarks, bookmark_item_p);
109 }
110
111 fclose(f);
112 rfm_rw_lock_writer_unlock(&bookmarks_lock);
113 return NULL;
114 }
115
116 static gpointer
save_bookmark_file_f(gpointer data)117 save_bookmark_file_f(gpointer data){
118 gchar *filename = get_bookmarks_filename();
119 rfm_rw_lock_writer_lock(&bookmarks_lock);
120 if (bookmarks==NULL || g_slist_length(bookmarks)==0){
121 if (rfm_g_file_test(filename, G_FILE_TEST_EXISTS)){
122 if (unlink(filename) < 0)
123 DBG("unlink(%s): %s\n", filename, strerror(errno));
124
125 }
126 rfm_rw_lock_writer_unlock(&bookmarks_lock);
127 g_free(filename);
128 return NULL;
129 }
130 FILE *f=fopen(filename, "w");
131 g_free(filename);
132 GSList *tmp=bookmarks;
133 if (f) {
134 for (;tmp && tmp->data; tmp=tmp->next){
135 bookmark_item_t *bookmark_item_p = tmp->data;
136 fprintf(f,"%s\n", bookmark_item_p->uri);
137 }
138 fclose(f);
139 }
140
141 rfm_rw_lock_writer_unlock(&bookmarks_lock);
142
143 gint bookmark_serial;
144 if (!getenv("RFM_BOOKMARK_SERIAL")||
145 strlen(getenv("RFM_BOOKMARK_SERIAL"))==0){
146 bookmark_serial = 0;
147 } else {
148 errno=0;
149 long li = strtol(getenv("RFM_BOOKMARK_SERIAL"), NULL, 10);
150 if (errno==ERANGE) bookmark_serial=0;
151 else bookmark_serial = li;
152 }
153
154
155 bookmark_serial++;
156 gchar *g=g_strdup_printf("%d", bookmark_serial);
157 if (rfm_rational (RFM_MODULE_DIR, "settings", (void *)"RFM_BOOKMARK_SERIAL", (void *)g, "mcs_set_var") == NULL){
158 rfm_setenv ("RFM_BOOKMARK_SERIAL", g, TRUE);
159 NOOP("cannot set RFM_BOOKMARK_SERIAL");
160 }
161 g_free(g);
162 NOOP("save_bookmark_file_f(): g_mutex_unlock\n");
163 return NULL;
164 }
165
166 static void
bookmarks_init(void)167 bookmarks_init(void){
168 static gsize initialization_value = 0;
169 if (g_once_init_enter (&initialization_value))
170 {
171 if (!bookmarks) read_bookmark_file_f(NULL);
172 g_once_init_leave (&initialization_value, 1);
173 }
174 }
175
176 static void
update_bookmark_icons(view_t * view_p,GSList ** oldlist_p)177 update_bookmark_icons (view_t * view_p, GSList **oldlist_p) {
178 if (rfm_get_gtk_thread() == g_thread_self()) g_error("update_bookmark_icons() is a thread function.\n");
179 bookmarks_init();
180 GSList *t;
181
182 // Construct a list of items to expose with altered
183 // bookmarks emblem
184 //
185 // Remove items which are unaltered from the refresh list.
186 rfm_rw_lock_reader_lock(&bookmarks_lock);
187 GSList *tm=bookmarks;
188 for (; tm && tm->data; tm=tm->next){
189 bookmark_item_t *bookmark_item_p = tm->data;
190 if (bookmark_item_p->path == NULL) continue;
191 gboolean found=FALSE;
192 if (!bookmark_item_p->path) continue;
193 for (t=*oldlist_p; t && t->data; t=t->next){
194 if (strcmp((gchar *)t->data, bookmark_item_p->path)==0){
195 // Remove items which are unaltered from the refresh list.
196 void *p=t->data;
197 *oldlist_p = g_slist_remove(*oldlist_p, t->data);
198 g_free(p);
199 found=TRUE;
200 break;
201 }
202 // Add new items to the refresh list.
203 if (!found) *oldlist_p = g_slist_prepend(*oldlist_p, g_strdup(bookmark_item_p->path));
204 }
205 }
206 rfm_rw_lock_reader_unlock(&bookmarks_lock);
207
208 // find and update records
209 if(!rfm_population_read_lock (view_p, "update_bookmark_icons")) goto done;
210 GSList *expose_list = NULL;
211 population_t **tmp = view_p->population_pp;
212 for(;tmp && *tmp; tmp++) {
213 population_t *population_p = *tmp;
214 if(population_p->en && population_p->en->path) {
215 for (t=*oldlist_p; t && t->data; t=t->next){
216 if (strcmp( population_p->en->path, (gchar *)t->data)==0){
217 GdkRectangle rect;
218 if (rfm_get_population_icon_rect(view_p, population_p, &rect)){
219 GdkRectangle *rect_p = (GdkRectangle *)malloc(sizeof(GdkRectangle));
220 if (!rect_p) g_error("malloc: %s\n", strerror(errno));
221 memset(rect_p, 0, sizeof(GdkRectangle));
222 memcpy(rect_p, &rect, sizeof(GdkRectangle));
223 expose_list = g_slist_prepend(expose_list, rect_p);
224 }
225 break;
226 }
227 }
228 }
229 }
230 rfm_population_read_unlock (view_p, "update_bookmark_icons");
231 for (t=expose_list; t && t->data; t=t->next){
232 GdkRectangle *rect_p = t->data;
233 rfm_expose_rect (view_p, rect_p);
234 g_free(rect_p);
235 }
236 g_slist_free(expose_list);
237 done:
238 //
239 // free oldlist
240 for (t=*oldlist_p; t && t->data; t=t->next){
241 g_free(t->data);
242 }
243 g_slist_free(*oldlist_p);
244 return;
245 }
246
247 void *
rodent_bookmark_monitor(view_t * view_p,void * data)248 rodent_bookmark_monitor(view_t *view_p, void *data){
249 //return NULL;
250 if(!getenv ("RFM_BOOKMARK_SERIAL") ||
251 !strlen (getenv ("RFM_BOOKMARK_SERIAL"))) return NULL;
252 if (rfm_get_gtk_thread() == g_thread_self())
253 g_error("rodent_bookmark_monitor() is a thread function.\n");
254 bookmarks_init();
255
256 NOOP("got bookmark serial=%s\n",getenv ("RFM_BOOKMARK_SERIAL"));
257 errno = 0;
258 struct stat st;
259 static time_t mtime=0;
260
261 gchar *filename = get_bookmarks_filename();
262 long value = strtol (getenv ("RFM_BOOKMARK_SERIAL"), NULL, 0);
263 if(errno != 0 || value != view_p->flags.bookmark_serial
264 ||(stat(filename, &st)==0 && st.st_mtime != mtime)) {
265 mtime = st.st_mtime;
266 TRACE("Bookmark serial= %d --> %ld\n",
267 view_p->flags.bookmark_serial, value);
268 view_p->flags.bookmark_serial = value;
269
270 // Here we create a new list of bookmark items to update
271 // icons which may be displayed with the bookmark emblem
272 GSList *oldlist=NULL;
273 rfm_rw_lock_writer_lock(&bookmarks_lock);
274 GSList *tmp=bookmarks;
275 for (; tmp && tmp->data; tmp=tmp->next){
276 bookmark_item_t *bookmark_item_p = tmp->data;
277 if (bookmark_item_p->path == NULL) continue;
278 oldlist = g_slist_prepend(oldlist, g_strdup(bookmark_item_p->path));
279 }
280 rfm_rw_lock_writer_unlock(&bookmarks_lock);
281
282 read_bookmark_file_f(NULL);
283 update_bookmark_icons (view_p, &oldlist);
284 }
285 g_free(filename);
286 return NULL;
287 }
288
289 gboolean
rodent_path_has_bookmark(const gchar * path)290 rodent_path_has_bookmark(const gchar *path){
291 rfm_global_t *rfm_global_p = rfm_global();
292 g_mutex_lock(rfm_global_p->status_mutex);
293 gint status = rfm_global_p->status;
294 g_mutex_unlock(rfm_global_p->status_mutex);
295 if(status == STATUS_EXIT) return FALSE;
296 if (!path || !strlen(path)) {
297 NOOP("rodent_path_has_bookmark() path is NULL or strlen==0");
298 return FALSE;
299 }
300 bookmarks_init();
301
302
303 gboolean retval = FALSE;
304 rfm_rw_lock_reader_lock(&bookmarks_lock);
305 GSList *tmp = bookmarks;
306 for (;rfm_global_p->status != STATUS_EXIT && tmp && tmp->data;
307 tmp=tmp->next){
308 bookmark_item_t *bookmark_item_p = tmp->data;
309 if (!bookmark_item_p->path) continue;
310 if (strcmp(bookmark_item_p->path, path)==0){
311 retval = TRUE;
312 break;
313 }
314 }
315 rfm_rw_lock_reader_unlock(&bookmarks_lock);
316 return retval;
317 }
318
319 GdkPixbuf *
rodent_get_bookmark_emblem(gint size)320 rodent_get_bookmark_emblem(gint size){
321 GdkPixbuf *bookmark_pixbuf =
322 rfm_get_pixbuf ("xffm/emblem_bookmark", size/3);
323 // Bookmark_pixbuf should never fail, nonetheless...
324 if (!bookmark_pixbuf) bookmark_pixbuf =
325 rfm_get_pixbuf ("xffm/emote_cool", size/3);
326 return bookmark_pixbuf;
327 }
328
329 gboolean
rodent_path_is_bookmarkable(const gchar * path)330 rodent_path_is_bookmarkable(const gchar *path){
331 if (!path || !strlen(path)) {
332 DBG("rodent_path_is_bookmarkable() path is NULL or strlen==0");
333 return FALSE;
334 }
335 if (!g_path_is_absolute(path)) return FALSE;
336 bookmarks_init();
337
338 GSList *tmp = bookmarks;
339 gboolean retval = TRUE;
340 rfm_rw_lock_reader_lock(&bookmarks_lock);
341 for (;tmp && tmp->data; tmp=tmp->next){
342 bookmark_item_t *bookmark_item_p = tmp->data;
343 if (!bookmark_item_p->path) continue;
344 // Is it already bookmarked?
345 if (strcmp(bookmark_item_p->path, path)==0){
346 retval = FALSE;
347 break;
348 }
349 }
350 rfm_rw_lock_reader_unlock(&bookmarks_lock);
351 return retval;
352 }
353
354 gboolean
rodent_bookmarks_add(const gchar * path)355 rodent_bookmarks_add(const gchar *path){
356 if (!path || !strlen(path)) {
357 DBG("rodent_bookmarks_add() path is NULL or strlen==0");
358 return FALSE;
359 }
360 bookmarks_init();
361 NOOP("Bookmarking %s\n", path);
362 bookmark_item_t *bookmark_item_p = bookmark_item_new();
363 bookmark_item_p->path = g_strdup(path);
364 GError *error = NULL;
365 bookmark_item_p->uri = g_filename_to_uri(path, NULL, &error);
366 if (error){
367 DBG("rodent_bookmarks_add(%s): %s\n", path, error->message);
368 g_error_free(error);
369 }
370
371 rfm_rw_lock_writer_lock(&bookmarks_lock);
372 bookmarks=g_slist_prepend(bookmarks, bookmark_item_p);
373 rfm_rw_lock_writer_unlock(&bookmarks_lock);
374 save_bookmark_file_f(NULL);
375 return TRUE;
376 }
377
378
379 gboolean
rodent_bookmarks_remove(const gchar * path)380 rodent_bookmarks_remove(const gchar *path){
381 if (!path || !strlen(path)) {
382 DBG("rodent_bookmarks_remove() path is NULL or strlen==0");
383 return FALSE;
384 }
385 bookmarks_init();
386 NOOP("removing Bookmark %s\n", path);
387 gboolean retval = FALSE;
388 rfm_rw_lock_writer_lock(&bookmarks_lock);
389 GSList *tmp=bookmarks;
390 for (;tmp && tmp->data; tmp=tmp->next){
391 bookmark_item_t *bookmark_item_p = tmp->data;
392 if (bookmark_item_p->path == NULL) continue;
393 if (strcmp(bookmark_item_p->path, path)==0){
394 NOOP("gotcha %s\n", path);
395 bookmarks = g_slist_remove(bookmarks, bookmark_item_p);
396 bookmark_item_free(bookmark_item_p);
397 retval = TRUE;
398 break;
399 }
400 }
401 rfm_rw_lock_writer_unlock(&bookmarks_lock);
402 if (retval) save_bookmark_file_f(NULL);
403 return retval;
404 }
405
406 void
rodent_bookmark_set_menuitems(widgets_t * widgets_p,const gchar * id)407 rodent_bookmark_set_menuitems(widgets_t *widgets_p, const gchar *id){
408 NOOP("rodent_bookmark_set_menuitems\n");
409 bookmarks_init();
410 gint level=0;
411 rfm_rw_lock_reader_lock(&bookmarks_lock);
412 GSList *local_list = NULL;
413 GSList *tmp=bookmarks;
414 for (;tmp && tmp->data; tmp=tmp->next){
415 bookmark_item_t *bookmark_item_p = tmp->data;
416 if (bookmark_item_p->path == NULL) continue;
417 local_list = g_slist_prepend(local_list, bookmark_item_p);
418 }
419 rfm_rw_lock_reader_unlock(&bookmarks_lock);
420
421 tmp=local_list;
422 for (;level < DEEPEST_BOOK_MENU_LEVELS && tmp && tmp->data; tmp=tmp->next){
423 bookmark_item_t *bookmark_item_p = tmp->data;
424 NOOP("setting bookmark item %d\n", level);
425 gchar *name = g_strdup_printf ("%s-%d", id, level);
426 GtkWidget *menuitem = rfm_get_widget (name);
427 if (!menuitem){
428 DBG("rodent_bookmark_set_menuitems(): widget %s not found", name);
429 g_free(name);
430 continue;
431 }
432 g_free(name);
433 if (!rfm_g_file_test(bookmark_item_p->path, G_FILE_TEST_IS_DIR)) {
434 TRACE("Invalid bookmark: %s (not a directory)\n", bookmark_item_p->path);
435 continue;
436 }
437 gchar *path=g_object_get_data(G_OBJECT(menuitem), "path");
438 g_object_set_data(G_OBJECT(menuitem), "path", g_strdup(bookmark_item_p->path));
439 g_free(path);
440
441 gchar *q = g_path_get_basename(bookmark_item_p->path);
442 rfm_replace_menu_label(menuitem, q);
443 g_free (q);
444
445 level++;
446 }
447 g_slist_free(local_list);
448
449 for (;level < DEEPEST_BOOK_MENU_LEVELS; level++){
450 gchar *name = g_strdup_printf ("%s-%d", id, level);
451 GtkWidget *menuitem = rfm_get_widget(name);
452 if (!menuitem){
453 DBG("rodent_bookmark_set_menuitems(): widget %s not found", name);
454 g_free(name);
455 continue;
456 }
457 g_free(name);
458 gchar *path=g_object_get_data(G_OBJECT(menuitem), "path");
459 g_object_set_data(G_OBJECT(menuitem), "path", NULL);
460 g_free(path);
461 if(GTK_IS_WIDGET(menuitem)) gtk_widget_hide(menuitem);
462 }
463 return;
464 }
465
466
467