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