source: lliurex-homework-harvester/trunk/fuentes/src/lhh-provider.c @ 2088

Last change on this file since 2088 was 2088, checked in by hectorgh, 3 years ago

wip on thunar plugin

File size: 13.6 KB
Line 
1/* vi:set et ai sw=2 sts=2 ts=2: */
2/*-
3 * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
4 * Copyright (c) 2011 Jannis Pohlmann <jannis@xfce.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22
23
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27
28#include <libxfce4util/libxfce4util.h>
29
30#include <src/lhh-backend.h>
31#include <src/lhh-provider.h>
32
33/* use g_access() on win32 */
34#if defined(G_OS_WIN32)
35#include <glib/gstdio.h>
36#else
37#define g_access(filename, mode) access((filename), (mode))
38#endif
39
40#include <pwd.h>
41
42
43static void   lhh_provider_menu_provider_init   (ThunarxMenuProviderIface *iface);
44static void   lhh_provider_finalize             (GObject                  *object);
45static GList *lhh_provider_get_file_actions     (ThunarxMenuProvider      *menu_provider,
46                                                 GtkWidget                *window,
47                                                 GList                    *files);
48
49static void   lhh_provider_execute              (LhhProvider              *lhh_provider,
50                                                 GPid                    (*action) (const gchar *folder,
51                                                                                    GList       *files,
52                                                                                    GtkWidget   *window,
53                                                                                    GError     **error),
54                                                 GtkWidget                *window,
55                                                 const gchar              *folder,
56                                                 GList                    *files,
57                                                 const gchar              *error_message);
58static void   lhh_provider_child_watch          (GPid                      pid,
59                                                 gint                      status,
60                                                 gpointer                  user_data);
61static void   lhh_provider_child_watch_destroy  (gpointer                  user_data);
62
63
64
65struct _LhhProviderClass
66{
67  GObjectClass __parent__;
68};
69
70struct _LhhProvider
71{
72  GObject         __parent__;
73
74#if !GTK_CHECK_VERSION(2,9,0)
75  /* GTK+ 2.9.0 and above provide an icon-name property
76   * for GtkActions, so we don't need the icon factory.
77   */
78  GtkIconFactory *icon_factory;
79#endif
80
81  /* child watch support for the last spawn command, which allowed us to refresh
82   * the folder contents after the command had terminated with ThunarVFS (i.e.
83   * when the archive had been created). This no longer works with GIO but
84   * we still use the watch to close the PID properly.
85   */
86  gint            child_watch_id;
87};
88
89
90static GQuark lhh_action_files_quark;
91#if THUNARX_CHECK_VERSION(0,4,1)
92static GQuark lhh_action_folder_quark;
93#endif
94static GQuark lhh_action_provider_quark;
95
96
97
98THUNARX_DEFINE_TYPE_WITH_CODE (LhhProvider,
99                               lhh_provider,
100                               G_TYPE_OBJECT,
101                               THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_MENU_PROVIDER,
102                                                            lhh_provider_menu_provider_init));
103
104
105static void
106lhh_provider_class_init (LhhProviderClass *klass)
107{
108  GObjectClass *gobject_class;
109
110  /* determine the "tap-action-files", "tap-action-folder" and "tap-action-provider" quarks */
111  lhh_action_files_quark = g_quark_from_string ("tap-action-files");
112#if THUNARX_CHECK_VERSION(0,4,1)
113  lhh_action_folder_quark = g_quark_from_string ("tap-action-folder");
114#endif
115  lhh_action_provider_quark = g_quark_from_string ("tap-action-provider");
116
117  gobject_class = G_OBJECT_CLASS (klass);
118  gobject_class->finalize = lhh_provider_finalize;
119}
120
121
122static void
123lhh_provider_menu_provider_init (ThunarxMenuProviderIface *iface)
124{
125  iface->get_file_actions = lhh_provider_get_file_actions;
126
127}
128
129
130
131static void
132lhh_provider_init (LhhProvider *lhh_provider)
133{
134        //
135}
136
137static void
138lhh_provider_finalize (GObject *object)
139{
140  LhhProvider *lhh_provider = LHH_PROVIDER (object);
141  GSource     *source;
142
143  /* give up maintaince of any pending child watch */
144  if (G_UNLIKELY (lhh_provider->child_watch_id != 0))
145    {
146      /* reset the callback function to g_spawn_close_pid() so the plugin can be
147       * safely unloaded and the child will still not become a zombie afterwards.
148       */
149      source = g_main_context_find_source_by_id (NULL, lhh_provider->child_watch_id);
150      g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL);
151    }
152 
153
154  (*G_OBJECT_CLASS (lhh_provider_parent_class)->finalize) (object);
155}
156
157
158static gboolean
159lhh_is_parent_writable (ThunarxFileInfo *file_info)
160{
161  gboolean result = FALSE;
162  gchar   *filename;
163  gchar   *uri;
164
165  /* determine the parent URI for the file info */
166  uri = thunarx_file_info_get_parent_uri (file_info);
167  if (G_LIKELY (uri != NULL))
168    {
169      /* determine the local filename for the URI */
170      filename = g_filename_from_uri (uri, NULL, NULL);
171      if (G_LIKELY (filename != NULL))
172        {
173          /* check if we can write to that folder */
174          result = (g_access (filename, W_OK) == 0);
175
176          /* release the filename */
177          g_free (filename);
178        }
179
180      /* release the URI */
181      g_free (uri);
182    }
183
184  return result;
185}
186
187static void
188lhh_send_file (GtkAction *action,
189                    GtkWidget *window)
190{
191  LhhProvider *lhh_provider;
192  GList       *files;
193  gchar       *dirname;
194  gchar       *uri;
195
196  /* determine the files associated with the action */
197  files = g_object_get_qdata (G_OBJECT (action), lhh_action_files_quark);
198  if (G_UNLIKELY (files == NULL))
199    return;
200
201  /* determine the provider associated with the action */
202  lhh_provider = g_object_get_qdata (G_OBJECT (action), lhh_action_provider_quark);
203  if (G_UNLIKELY (lhh_provider == NULL))
204    return;
205
206  /* determine the parent URI of the first selected file */
207  uri = thunarx_file_info_get_parent_uri (files->data);
208  if (G_UNLIKELY (uri == NULL))
209    return;
210
211  /* determine the directory of the first selected file */
212  dirname = g_filename_from_uri (uri, NULL, NULL);
213  g_free (uri);
214
215  /* verify that we were able to determine a local path */
216  if (G_UNLIKELY (dirname == NULL))
217    return;
218
219  /* execute the action */
220  lhh_provider_execute (lhh_provider, lhh_backend_send_file, window, dirname, files, _("Failed to create archive"));
221
222  /* cleanup */
223  g_free (dirname);
224}
225
226static void
227lhh_receive_files (GtkAction *action,
228                    GtkWidget *window)
229{
230  LhhProvider *lhh_provider;
231  GList       *files;
232  gchar       *dirname;
233  gchar       *uri;
234
235  /* determine the files associated with the action */
236  files = g_object_get_qdata (G_OBJECT (action), lhh_action_files_quark);
237  if (G_UNLIKELY (files == NULL))
238    return;
239
240  /* determine the provider associated with the action */
241  lhh_provider = g_object_get_qdata (G_OBJECT (action), lhh_action_provider_quark);
242  if (G_UNLIKELY (lhh_provider == NULL))
243    return;
244
245  /* determine the parent URI of the first selected file */
246  uri = thunarx_file_info_get_parent_uri (files->data);
247  if (G_UNLIKELY (uri == NULL))
248    return;
249
250  /* determine the directory of the first selected file */
251  dirname = g_filename_from_uri (uri, NULL, NULL);
252  g_free (uri);
253
254  /* verify that we were able to determine a local path */
255  if (G_UNLIKELY (dirname == NULL))
256    return;
257
258  /* execute the action */
259  lhh_provider_execute (lhh_provider, lhh_backend_receive_files, window, dirname, files, _("Failed to create archive"));
260
261  /* cleanup */
262  g_free (dirname);
263}
264
265
266
267static GList*
268lhh_provider_get_file_actions (ThunarxMenuProvider *menu_provider,
269                               GtkWidget           *window,
270                               GList               *files)
271{
272  gchar              *scheme;
273  LhhProvider        *lhh_provider = LHH_PROVIDER (menu_provider);
274  GtkAction          *action;
275  GClosure           *closure;
276  gboolean            all_archives = TRUE;
277  gboolean            can_write = TRUE;
278  GList              *actions = NULL;
279  GList              *lp;
280  gint                n_files = 0;
281  uid_t uid;
282  gboolean is_dir;
283  struct passwd *pw;
284
285  /* check all supplied files */
286  for (lp = files; lp != NULL; lp = lp->next, ++n_files)
287    {
288      /* check if the file is a local file */
289      scheme = thunarx_file_info_get_uri_scheme (lp->data);
290      is_dir=thunarx_file_info_is_directory(lp->data);
291     
292       
293      /* unable to handle non-local files */
294      if (G_UNLIKELY (strcmp (scheme, "file")))
295        {
296          g_free (scheme);
297          return NULL;
298        }
299      g_free (scheme);
300
301     
302      /* check if we can write to the parent folder */
303      if (can_write && !lhh_is_parent_writable (lp->data))
304        can_write = FALSE;
305    }
306
307     
308        uid = geteuid ();
309        pw = getpwuid (uid);
310        if (pw)
311        {
312       
313                if(pw->pw_uid < 1003)
314                {
315                        return NULL;
316                }
317                else
318                {
319                       
320       
321                                    if(!is_dir){
322                                       
323                                    action = g_object_new (GTK_TYPE_ACTION,
324                                                             "label", _("QUE TE JODAN"),
325                                                             "name", "Lhh::send-file",
326                                #if !GTK_CHECK_VERSION(2,9,0)
327                                                             "stock-id", "tap-extract-to",
328                                #else
329                                                             "icon-name", "tap-extract-to",
330                                #endif
331                                                             "tooltip", dngettext (GETTEXT_PACKAGE,
332                                                                                   "Por aqui",
333                                                                                   "Por aqui ssss",
334                                                                                   n_files),
335                                                             NULL);
336                                           
337                                        closure = g_cclosure_new_object (G_CALLBACK (lhh_send_file), G_OBJECT (window));
338                                    }
339                                    else
340                                    {
341                                       
342                                            action = g_object_new (GTK_TYPE_ACTION,
343                                                             "label", _("UN POQUITO"),
344                                                             "name", "Lhh::send-file",
345                                #if !GTK_CHECK_VERSION(2,9,0)
346                                                             "stock-id", "tap-extract-to",
347                                #else
348                                                             "icon-name", "tap-extract-to",
349                                #endif
350                                                             "tooltip", dngettext (GETTEXT_PACKAGE,
351                                                                                   "Por aqui",
352                                                                                   "Por aqui ssss",
353                                                                                   n_files),
354                                                             NULL);
355                                           
356                                        closure = g_cclosure_new_object (G_CALLBACK (lhh_receive_files), G_OBJECT (window));
357                                    }
358                                      g_object_set_qdata_full (G_OBJECT (action), lhh_action_files_quark,
359                                                               thunarx_file_info_list_copy (files),
360                                                               (GDestroyNotify) thunarx_file_info_list_free);
361                                      g_object_set_qdata_full (G_OBJECT (action), lhh_action_provider_quark,
362                                                               g_object_ref (G_OBJECT (lhh_provider)),
363                                                               (GDestroyNotify) g_object_unref);
364                                       
365                                     
366                                      g_signal_connect_closure (G_OBJECT (action), "activate", closure, TRUE);
367                                      actions = g_list_append (actions, action);                       
368                       
369                }
370               
371        }
372       
373  return actions;
374}
375
376
377static void
378lhh_provider_execute (LhhProvider *lhh_provider,
379                      GPid       (*action) (const gchar *folder,
380                                            GList       *files,
381                                            GtkWidget   *window,
382                                            GError     **error),
383                      GtkWidget   *window,
384                      const gchar *folder,
385                      GList       *files,
386                      const gchar *error_message)
387{
388  GtkWidget *dialog;
389  GSource   *source;
390  GError    *error = NULL;
391  GPid       pid;
392
393  /* try to execute the action */
394  pid = (*action) (folder, files, window, &error);
395  if (G_LIKELY (pid >= 0))
396    {
397      /* check if we already have a child watch */
398      if (G_UNLIKELY (lhh_provider->child_watch_id != 0))
399        {
400          /* reset the callback function to g_spawn_close_pid() so the plugin can be
401           * safely unloaded and the child will still not become a zombie afterwards.
402           */
403          source = g_main_context_find_source_by_id (NULL, lhh_provider->child_watch_id);
404          g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL);
405        }
406
407      /* schedule the new child watch */
408      lhh_provider->child_watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, lhh_provider_child_watch,
409                                                             lhh_provider, lhh_provider_child_watch_destroy);
410    }
411  else if (error != NULL)
412    {
413      /* display an error dialog */
414      dialog = gtk_message_dialog_new (GTK_WINDOW (window),
415                                       GTK_DIALOG_DESTROY_WITH_PARENT
416                                       | GTK_DIALOG_MODAL,
417                                       GTK_MESSAGE_ERROR,
418                                       GTK_BUTTONS_CLOSE,
419                                       "%s.", error_message);
420      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
421      gtk_dialog_run (GTK_DIALOG (dialog));
422      gtk_widget_destroy (dialog);
423      g_error_free (error);
424    }
425}
426
427
428
429static void
430lhh_provider_child_watch (GPid     pid,
431                          gint     status,
432                          gpointer user_data)
433{
434  GDK_THREADS_ENTER ();
435
436  /* need to cleanup */
437  g_spawn_close_pid (pid);
438
439  GDK_THREADS_LEAVE ();
440}
441
442
443
444static void
445lhh_provider_child_watch_destroy (gpointer user_data)
446{
447  LhhProvider *lhh_provider = LHH_PROVIDER (user_data);
448
449  /* reset child watch id */
450  lhh_provider->child_watch_id = 0;
451}
452
453
454
Note: See TracBrowser for help on using the repository browser.