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

Last change on this file since 2093 was 2093, checked in by hectorgh, 4 years ago

wip

File size: 14.4 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 ("lhh-action-files");
112#if THUNARX_CHECK_VERSION(0,4,1)
113  lhh_action_folder_quark = g_quark_from_string ("lhh-action-folder");
114#endif
115  lhh_action_provider_quark = g_quark_from_string ("lhh-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
187
188static void
189lhh_send_file (GtkAction *action,
190                    GtkWidget *window)
191{
192  LhhProvider *lhh_provider;
193  GList       *files;
194  gchar       *dirname;
195  gchar       *uri;
196
197  /* determine the files associated with the action */
198  files = g_object_get_qdata (G_OBJECT (action), lhh_action_files_quark);
199  if (G_UNLIKELY (files == NULL))
200    return;
201
202  /* determine the provider associated with the action */
203  lhh_provider = g_object_get_qdata (G_OBJECT (action), lhh_action_provider_quark);
204  if (G_UNLIKELY (lhh_provider == NULL))
205    return;
206
207  /* determine the parent URI of the first selected file */
208  uri = thunarx_file_info_get_parent_uri (files->data);
209  if (G_UNLIKELY (uri == NULL))
210    return;
211
212  /* determine the directory of the first selected file */
213  dirname = g_filename_from_uri (uri, NULL, NULL);
214  g_free (uri);
215
216  /* verify that we were able to determine a local path */
217  if (G_UNLIKELY (dirname == NULL))
218    return;
219
220  /* execute the action */
221  lhh_provider_execute (lhh_provider, lhh_backend_send_file, window, dirname, files, _("Failed to create archive"));
222
223  /* cleanup */
224  g_free (dirname);
225}
226
227static void
228lhh_receive_files (GtkAction *action,
229                    GtkWidget *window)
230{
231  LhhProvider *lhh_provider;
232  GList       *files;
233  gchar       *dirname;
234  gchar       *uri;
235
236  /* determine the files associated with the action */
237  files = g_object_get_qdata (G_OBJECT (action), lhh_action_files_quark);
238  if (G_UNLIKELY (files == NULL))
239    return;
240
241  /* determine the provider associated with the action */
242  lhh_provider = g_object_get_qdata (G_OBJECT (action), lhh_action_provider_quark);
243  if (G_UNLIKELY (lhh_provider == NULL))
244    return;
245
246  /* determine the parent URI of the first selected file */
247  uri = thunarx_file_info_get_parent_uri (files->data);
248  if (G_UNLIKELY (uri == NULL))
249    return;
250
251  /* determine the directory of the first selected file */
252  dirname = g_filename_from_uri (uri, NULL, NULL);
253  g_free (uri);
254
255  /* verify that we were able to determine a local path */
256  if (G_UNLIKELY (dirname == NULL))
257    return;
258
259  /* execute the action */
260  lhh_provider_execute (lhh_provider, lhh_backend_receive_files, window, dirname, files, _("Failed to create archive"));
261
262  /* cleanup */
263  g_free (dirname);
264}
265
266
267
268static GList*
269lhh_provider_get_file_actions (ThunarxMenuProvider *menu_provider,
270                               GtkWidget           *window,
271                               GList               *files)
272{
273  gchar              *scheme;
274  LhhProvider        *lhh_provider = LHH_PROVIDER (menu_provider);
275  GtkAction          *action;
276  GClosure           *closure;
277  gboolean            all_archives = TRUE;
278  gboolean            can_write = TRUE;
279  GList              *actions = NULL;
280  GList              *lp;
281  gint                n_files = 0;
282  uid_t uid;
283  gboolean is_dir;
284  gboolean is_writable;
285  struct passwd *pw;
286
287  /* check all supplied files */
288  for (lp = files; lp != NULL; lp = lp->next, ++n_files)
289    {
290      /* check if the file is a local file */
291      scheme = thunarx_file_info_get_uri_scheme (lp->data);
292      is_dir=thunarx_file_info_is_directory(lp->data);
293     
294       
295      /* unable to handle non-local files */
296      if (G_UNLIKELY (strcmp (scheme, "file")))
297        {
298          g_free (scheme);
299          return NULL;
300        }
301      g_free (scheme);
302
303     
304      /* check if we can write to the parent folder */
305      if (can_write && !lhh_is_parent_writable (lp->data))
306        can_write = FALSE;
307
308      is_writable=lhh_is_parent_writable(lp->data);
309
310    }
311
312     
313        uid = geteuid ();
314        pw = getpwuid (uid);
315        if (pw)
316        {
317       
318                if(pw->pw_uid < 1003)
319                {
320                        return NULL;
321                }
322                else
323                {
324                       
325       
326                                    if(!is_dir){
327                                       
328                                     if (is_writable)
329                                     {
330                                           
331                                    action = g_object_new (GTK_TYPE_ACTION,
332                                                             "label", _("Send file to teacher"),
333                                                             "name", "Lhh::send-file",
334                                #if !GTK_CHECK_VERSION(2,9,0)
335                                                             "stock-id", "go-jump",
336                                #else
337                                                             "icon-name", "tap-extract-to",
338                                #endif
339                                                             "tooltip", dngettext (GETTEXT_PACKAGE,
340                                                                                   "Send file to teacher",
341                                                                                   "Send file to teacher",
342                                                                                   n_files),
343                                                             NULL);
344                                           
345                                        closure = g_cclosure_new_object (G_CALLBACK (lhh_send_file), G_OBJECT (window));
346                                         g_object_set_qdata_full (G_OBJECT (action), lhh_action_files_quark,
347                                                               thunarx_file_info_list_copy (files),
348                                                               (GDestroyNotify) thunarx_file_info_list_free);
349                                      g_object_set_qdata_full (G_OBJECT (action), lhh_action_provider_quark,
350                                                               g_object_ref (G_OBJECT (lhh_provider)),
351                                                               (GDestroyNotify) g_object_unref);
352                                       
353                                     
354                                      g_signal_connect_closure (G_OBJECT (action), "activate", closure, TRUE);
355                                      actions = g_list_append (actions, action);       
356                                        }
357                                    }
358                                    else
359                                    {
360
361                                        if (is_writable)
362                                        {
363                                       
364                                            action = g_object_new (GTK_TYPE_ACTION,
365                                                             "label", _("Set this folder to receive homeworks"),
366                                                             "name", "Lhh::receive-file",
367                                #if !GTK_CHECK_VERSION(2,9,0)
368                                                             "stock-id", "go-jump",
369                                #else
370                                                             "icon-name", "tap-extract-to",
371                                #endif
372                                                             "tooltip", dngettext (GETTEXT_PACKAGE,
373                                                                                   "Set this folder to receive homeworks",
374                                                                                   "Set this folder to receive homeworks",
375                                                                                   n_files),
376                                                             NULL);
377                                           
378                                        closure = g_cclosure_new_object (G_CALLBACK (lhh_receive_files), G_OBJECT (window));
379                                               
380                                        g_object_set_qdata_full (G_OBJECT (action), lhh_action_files_quark,
381                                                               thunarx_file_info_list_copy (files),
382                                                               (GDestroyNotify) thunarx_file_info_list_free);
383                                      g_object_set_qdata_full (G_OBJECT (action), lhh_action_provider_quark,
384                                                               g_object_ref (G_OBJECT (lhh_provider)),
385                                                               (GDestroyNotify) g_object_unref);
386                                       
387                                     
388                                      g_signal_connect_closure (G_OBJECT (action), "activate", closure, TRUE);
389                                      actions = g_list_append (actions, action);                                               
390
391                                               
392                                               
393                                        }
394                                    }
395                                               
396                       
397                }
398               
399        }
400       
401  return actions;
402}
403
404
405static void
406lhh_provider_execute (LhhProvider *lhh_provider,
407                      GPid       (*action) (const gchar *folder,
408                                            GList       *files,
409                                            GtkWidget   *window,
410                                            GError     **error),
411                      GtkWidget   *window,
412                      const gchar *folder,
413                      GList       *files,
414                      const gchar *error_message)
415{
416  GtkWidget *dialog;
417  GSource   *source;
418  GError    *error = NULL;
419  GPid       pid;
420
421  /* try to execute the action */
422  pid = (*action) (folder, files, window, &error);
423  if (G_LIKELY (pid >= 0))
424    {
425      /* check if we already have a child watch */
426      if (G_UNLIKELY (lhh_provider->child_watch_id != 0))
427        {
428          /* reset the callback function to g_spawn_close_pid() so the plugin can be
429           * safely unloaded and the child will still not become a zombie afterwards.
430           */
431          source = g_main_context_find_source_by_id (NULL, lhh_provider->child_watch_id);
432          g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL);
433        }
434
435      /* schedule the new child watch */
436      lhh_provider->child_watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, lhh_provider_child_watch,
437                                                             lhh_provider, lhh_provider_child_watch_destroy);
438    }
439  else if (error != NULL)
440    {
441      /* display an error dialog */
442      dialog = gtk_message_dialog_new (GTK_WINDOW (window),
443                                       GTK_DIALOG_DESTROY_WITH_PARENT
444                                       | GTK_DIALOG_MODAL,
445                                       GTK_MESSAGE_ERROR,
446                                       GTK_BUTTONS_CLOSE,
447                                       "%s.", error_message);
448      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
449      gtk_dialog_run (GTK_DIALOG (dialog));
450      gtk_widget_destroy (dialog);
451      g_error_free (error);
452    }
453}
454
455
456
457static void
458lhh_provider_child_watch (GPid     pid,
459                          gint     status,
460                          gpointer user_data)
461{
462  GDK_THREADS_ENTER ();
463
464  /* need to cleanup */
465  g_spawn_close_pid (pid);
466
467  GDK_THREADS_LEAVE ();
468}
469
470
471
472static void
473lhh_provider_child_watch_destroy (gpointer user_data)
474{
475  LhhProvider *lhh_provider = LHH_PROVIDER (user_data);
476
477  /* reset child watch id */
478  lhh_provider->child_watch_id = 0;
479}
480
481
482
Note: See TracBrowser for help on using the repository browser.