~didrocks/ubuntuone-client/dont-suffer-zg-crash

« back to all changes in this revision

Viewing changes to nautilus/ubuntuone-nautilus.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2009-06-30 12:00:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090630120000-by806ovmw3193qe8
Tags: upstream-0.90.3
ImportĀ upstreamĀ versionĀ 0.90.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ubuntuone-nautilus.c - Nautilus extensions for Ubuntu One
 
3
 *
 
4
 * Authors: Tim Cole <tim.cole@canonical.com>
 
5
 *          Rodney Dawes <rodney.dawes@canonical.com>
 
6
 *
 
7
 * Copyright 2009 Canonical Ltd.
 
8
 *
 
9
 * This program is free software: you can redistribute it and/or modify it
 
10
 * under the terms of the GNU General Public License version 3, as published
 
11
 * by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
15
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
16
 * PURPOSE.  See the GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License along
 
19
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 */
 
22
 
 
23
#ifdef HAVE_CONFIG_H
 
24
#include <config.h>
 
25
#endif
 
26
 
 
27
#include <glib/gi18n-lib.h>
 
28
 
 
29
#include <dbus/dbus-glib.h>
 
30
 
 
31
#include <libnautilus-extension/nautilus-extension-types.h>
 
32
#include <libnautilus-extension/nautilus-file-info.h>
 
33
#include <libnautilus-extension/nautilus-info-provider.h>
 
34
#include <libnautilus-extension/nautilus-menu-provider.h>
 
35
#include <libnautilus-extension/nautilus-location-widget-provider.h>
 
36
 
 
37
#include <fcntl.h>
 
38
#include <string.h>
 
39
#include <sys/stat.h>
 
40
#include <sys/types.h>
 
41
 
 
42
#define UBUNTUONE_TYPE_NAUTILUS  (ubuntuone_nautilus_get_type ())
 
43
#define UBUNTUONE_NAUTILUS(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), UBUNTUONE_TYPE_NAUTILUS, UbuntuOneNautilus))
 
44
 
 
45
typedef struct {
 
46
  GObject parent_slot;
 
47
 
 
48
  DBusGConnection * bus;
 
49
  DBusGProxy * u1_proxy;
 
50
  DBusGProxy * u1_status;
 
51
  DBusGProxy * u1_shares;
 
52
  DBusGProxy * u1_fs;
 
53
 
 
54
  /* Are we connected? */
 
55
  gboolean connected;
 
56
 
 
57
  /* The managed directory root */
 
58
  gchar * managed;
 
59
 
 
60
  /* Buttons, because we need a different one for each view */
 
61
  GHashTable * buttons;
 
62
 
 
63
  /* Lists of ul/dl/shares for setting emblems */
 
64
  GHashTable * uploads;
 
65
  GHashTable * downloads;
 
66
  GHashTable * shares;
 
67
} UbuntuOneNautilus;
 
68
 
 
69
typedef struct {
 
70
  GObjectClass parent_slot;
 
71
} UbuntuOneNautilusClass;
 
72
 
 
73
static void ubuntuone_nautilus_finalize(GObject * object);
 
74
 
 
75
static GType ubuntuone_nautilus_get_type (void);
 
76
static void ubuntuone_nautilus_register_type (GTypeModule * module);
 
77
 
 
78
/* DBus signal and async method call handlers */
 
79
static void ubuntuone_nautilus_share_metadata (DBusGProxy * proxy,
 
80
                                               DBusGProxyCall * call_id,
 
81
                                               gpointer user_data);
 
82
static void ubuntuone_nautilus_state_toggled (DBusGProxy * proxy,
 
83
                                              DBusGProxyCall * call_id,
 
84
                                              gpointer user_data);
 
85
static void ubuntuone_nautilus_got_root (DBusGProxy * proxy,
 
86
                                         DBusGProxyCall * call_id,
 
87
                                         gpointer user_data);
 
88
static void ubuntuone_nautilus_got_shared (DBusGProxy * proxy,
 
89
                                           DBusGProxyCall * call_id,
 
90
                                           gpointer user_data);
 
91
static void ubuntuone_nautilus_status_changed (DBusGProxy * proxy,
 
92
                                               GHashTable * hash,
 
93
                                               gpointer user_data);
 
94
static void ubuntuone_nautilus_upload_started (DBusGProxy * proxy,
 
95
                                               gchar * path,
 
96
                                               gpointer user_data);
 
97
static void ubuntuone_nautilus_upload_finished (DBusGProxy * proxy,
 
98
                                                 gchar * path,
 
99
                                                 gpointer user_data);
 
100
static void ubuntuone_nautilus_download_started (DBusGProxy * proxy,
 
101
                                                 gchar * path,
 
102
                                                 gpointer user_data);
 
103
static void ubuntuone_nautilus_download_finished (DBusGProxy * proxy,
 
104
                                                  gchar * path,
 
105
                                                  gpointer user_data);
 
106
static void ubuntuone_nautilus_share_created (DBusGProxy * proxy,
 
107
                                              GHashTable * hash,
 
108
                                              gpointer user_data);
 
109
 
 
110
static GObjectClass * parent_class = NULL;
 
111
 
 
112
/* Are we in an Ubuntu One managed directory */
 
113
static gboolean ubuntuone_is_storagefs (UbuntuOneNautilus * uon,
 
114
                                        const char * path) {
 
115
  gboolean managed = FALSE;
 
116
  gchar * dirpath;
 
117
 
 
118
  if (!uon->managed)
 
119
    return FALSE;
 
120
 
 
121
  if (!path)
 
122
    return FALSE;
 
123
 
 
124
  if (strcmp (path, uon->managed) == 0)
 
125
    return TRUE;
 
126
 
 
127
  dirpath = g_strdup_printf ("%s/", uon->managed);
 
128
  if (strncmp (path, dirpath, strlen (dirpath)) == 0)
 
129
    managed = TRUE;
 
130
 
 
131
  g_free (dirpath);
 
132
 
 
133
  return managed;
 
134
}
 
135
 
 
136
/* Update file info provider */
 
137
static NautilusOperationResult ubuntuone_nautilus_update_file_info (NautilusInfoProvider * provider,
 
138
                                                                    NautilusFileInfo * file,
 
139
                                                                    GClosure * update_complete,
 
140
                                                                    NautilusOperationHandle ** handle) {
 
141
  UbuntuOneNautilus * uon;
 
142
  gchar * share_status = NULL;
 
143
  char * path = NULL;
 
144
  int size = 0, ret = 0;
 
145
 
 
146
  uon = UBUNTUONE_NAUTILUS(provider);
 
147
 
 
148
  path = g_filename_from_uri (nautilus_file_info_get_uri (file), NULL, NULL);
 
149
 
 
150
  if (g_hash_table_lookup (uon->uploads, path))
 
151
    nautilus_file_info_add_emblem (file, "ubuntuone-uploading");
 
152
 
 
153
  if (g_hash_table_lookup (uon->downloads, path))
 
154
    nautilus_file_info_add_emblem (file, "ubuntuone-downloading");
 
155
 
 
156
  if (g_hash_table_lookup (uon->shares, path))
 
157
    nautilus_file_info_add_emblem (file, "shared");
 
158
 
 
159
  return NAUTILUS_OPERATION_COMPLETE;
 
160
}
 
161
 
 
162
static void ubuntuone_nautilus_info_provider_iface_init (NautilusInfoProviderIface * iface) {
 
163
  iface->update_file_info = ubuntuone_nautilus_update_file_info;
 
164
}
 
165
 
 
166
/* LocationWidget callbacks */
 
167
static void ubuntuone_nautilus_button_clicked (GtkButton * button,
 
168
                                               gpointer user_data) {
 
169
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
170
 
 
171
  if (uon->connected)
 
172
    dbus_g_proxy_begin_call (uon->u1_proxy, "disconnect",
 
173
                             ubuntuone_nautilus_state_toggled, NULL,
 
174
                             NULL, G_TYPE_INVALID);
 
175
  else
 
176
    dbus_g_proxy_begin_call (uon->u1_proxy, "connect",
 
177
                             ubuntuone_nautilus_state_toggled, NULL,
 
178
                             NULL, G_TYPE_INVALID);
 
179
}
 
180
 
 
181
static void ubuntuone_nautilus_button_destroyed (GtkObject * button,
 
182
                                                 gpointer user_data) {
 
183
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
184
  gchar * path;
 
185
 
 
186
  /* Magic bag of holding +10:
 
187
   * Get the path so we can remove the button from the hash table
 
188
   */
 
189
  path = g_object_steal_data (G_OBJECT (button), "uon-path");
 
190
  g_hash_table_remove (uon->buttons, path);
 
191
 
 
192
  g_free (path);
 
193
}
 
194
 
 
195
/* LocationWidget provider */
 
196
static GtkWidget * ubuntuone_nautilus_get_location_widget(NautilusLocationWidgetProvider * provider,
 
197
                                                          const char * uri,
 
198
                                                          GtkWidget * parent) {
 
199
  UbuntuOneNautilus * uon;
 
200
  gchar * path;
 
201
  GtkWidget * hbox = NULL;
 
202
  GtkWidget * label, * button;
 
203
  gchar * labeltext;
 
204
 
 
205
  uon = UBUNTUONE_NAUTILUS (provider);
 
206
 
 
207
  path = g_filename_from_uri (uri, NULL, NULL);
 
208
 
 
209
  if (!ubuntuone_is_storagefs (uon, path))
 
210
    goto location_done;
 
211
 
 
212
  hbox = gtk_hbox_new (FALSE, 6);
 
213
  labeltext = g_strdup_printf ("<b>Ubuntu One</b> %s", _("File Sharing"));
 
214
  label = gtk_label_new (labeltext);
 
215
  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
 
216
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 
217
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
 
218
  gtk_widget_show (label);
 
219
 
 
220
  /* Create a button and stick it in the hash, if we don't have one already */
 
221
  button = g_hash_table_lookup (uon->buttons, path);
 
222
  if (!button) {
 
223
    button = gtk_button_new_with_label (_("Connect"));
 
224
    /* Magic bag of holding +10:
 
225
     * We have to set the path as data on the object, to remove the button
 
226
     * from the hash table when it is destroyed (window close, etc...)
 
227
     */
 
228
    g_object_set_data_full (G_OBJECT (button), "uon-path",
 
229
                            g_strdup (path), g_free);
 
230
    g_hash_table_replace (uon->buttons, g_strdup (path), button);
 
231
 
 
232
    g_signal_connect (button, "destroy",
 
233
                      G_CALLBACK (ubuntuone_nautilus_button_destroyed), uon);
 
234
    g_signal_connect (button, "clicked",
 
235
                      G_CALLBACK (ubuntuone_nautilus_button_clicked), uon);
 
236
    gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
 
237
  }
 
238
  gtk_widget_show (button);
 
239
 
 
240
  gtk_widget_show (hbox);
 
241
 
 
242
 location_done:
 
243
  g_free (path);
 
244
 
 
245
  return hbox;
 
246
}
 
247
 
 
248
static void ubuntuone_nautilus_bar_provider_iface_init (NautilusLocationWidgetProviderIface * iface) {
 
249
  iface->get_widget = ubuntuone_nautilus_get_location_widget;
 
250
}
 
251
 
 
252
/* Magical struct for passing data in sharing callbacks */
 
253
struct _ShareCBData {
 
254
  UbuntuOneNautilus * uon;
 
255
  gchar * path;
 
256
  GtkWidget * parent;
 
257
 
 
258
  /* Share dialog widgets */
 
259
  GtkWidget * user_entry;
 
260
  GtkWidget * name_entry;
 
261
  GtkWidget * allow_mods;
 
262
};
 
263
 
 
264
static void __share_cb_data_free (struct _ShareCBData * data) {
 
265
  data->uon = NULL;
 
266
  data->parent = NULL;
 
267
 
 
268
  g_free (data->path);
 
269
  data->path = NULL;
 
270
 
 
271
  g_free (data);
 
272
 
 
273
  data = NULL;
 
274
}
 
275
 
 
276
/* Share on Ubuntu One dialog constructor */
 
277
static GtkWidget * ubuntuone_nautilus_share_dialog_construct (struct _ShareCBData * data) {
 
278
  GtkWidget * dialog;
 
279
  GtkWidget * area, * table, * label;
 
280
 
 
281
  dialog = gtk_dialog_new ();
 
282
  gtk_window_set_title (GTK_WINDOW (dialog), _("Share on Ubuntu One"));
 
283
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (data->parent));
 
284
  gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
 
285
  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
 
286
  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
 
287
                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
288
                          ("Share"), GTK_RESPONSE_ACCEPT,
 
289
                          NULL);
 
290
  gtk_dialog_set_default_response (GTK_DIALOG (dialog),
 
291
                                   GTK_RESPONSE_ACCEPT);
 
292
  gtk_window_set_icon_name (GTK_WINDOW (dialog), "ubuntuone-client");
 
293
 
 
294
  area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
295
 
 
296
  table = gtk_table_new (3, 2, FALSE);
 
297
  gtk_table_set_row_spacings (GTK_TABLE (table), 12);
 
298
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
299
  gtk_container_set_border_width (GTK_CONTAINER (table), 7);
 
300
  gtk_widget_show (table);
 
301
  gtk_container_add (GTK_CONTAINER (area), table);
 
302
 
 
303
  label = gtk_label_new (_("Share _with (e-mail):"));
 
304
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 
305
  gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
 
306
  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
 
307
  gtk_widget_show (label);
 
308
 
 
309
  data->user_entry = gtk_entry_new ();
 
310
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), data->user_entry);
 
311
  gtk_table_attach_defaults (GTK_TABLE (table), data->user_entry, 1, 2, 0, 1);
 
312
  gtk_widget_show (data->user_entry);
 
313
 
 
314
  label = gtk_label_new (_("Share _Name:"));
 
315
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 
316
  gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
 
317
  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
 
318
  gtk_widget_show (label);
 
319
 
 
320
  data->name_entry = gtk_entry_new ();
 
321
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), data->name_entry);
 
322
  gtk_table_attach_defaults (GTK_TABLE (table), data->name_entry, 1, 2, 1, 2);
 
323
  gtk_widget_show (data->name_entry);
 
324
 
 
325
  data->allow_mods = gtk_check_button_new_with_mnemonic (_("_Allow Modification"));
 
326
  gtk_table_attach_defaults (GTK_TABLE (table), data->allow_mods, 0, 2, 2, 3);
 
327
  gtk_widget_show (data->allow_mods);
 
328
 
 
329
  return dialog;
 
330
}
 
331
 
 
332
/* Struct for post data for creating a share */
 
333
struct _SharePostData {
 
334
  gchar * email;
 
335
  gchar * name;
 
336
  gboolean modify;
 
337
};
 
338
 
 
339
static void __share_post_data_free (struct _SharePostData * data) {
 
340
  g_free (data->email);
 
341
  data->email = NULL;
 
342
 
 
343
  g_free (data->name);
 
344
  data->name = NULL;
 
345
 
 
346
  g_free (data);
 
347
  data = NULL;
 
348
}
 
349
 
 
350
/* Menu callbacks */
 
351
static void ubuntuone_nautilus_share_dialog_response (GtkDialog * dialog,
 
352
                                                      gint response,
 
353
                                                      gpointer user_data) {
 
354
  struct _ShareCBData * data = (struct _ShareCBData *) user_data;
 
355
 
 
356
  switch (response) {
 
357
  case GTK_RESPONSE_ACCEPT: {
 
358
    struct _SharePostData * pdata = g_new0 (struct _SharePostData, 1);
 
359
 
 
360
    pdata->email = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->user_entry)));
 
361
    pdata->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry)));
 
362
    pdata->modify = gtk_check_box_get_active (GTK_CHECK_BOX (data->allow_mods));
 
363
 
 
364
    dbus_g_proxy_begin_call (data->uon->u1_fs, "get_metadata",
 
365
                             ubuntuone_nautilus_share_metadata, pdata,
 
366
                             NULL,
 
367
                             G_TYPE_STRING, data->path,
 
368
                             G_TYPE_INVALID);
 
369
  }
 
370
  default:
 
371
    gtk_widget_destroy (GTK_WIDGET (dialog));
 
372
    break;
 
373
  }
 
374
  __share_cb_data_free (data);
 
375
}
 
376
 
 
377
static void ubuntuone_nautilus_share_dialog_closed (GtkDialog * dialog,
 
378
                                                    gpointer user_data) {
 
379
  ubuntuone_nautilus_share_dialog_response (dialog, GTK_RESPONSE_CANCEL,
 
380
                                            user_data);
 
381
}
 
382
 
 
383
static void ubuntuone_nautilus_share_folder (NautilusMenuItem * item,
 
384
                                             gpointer * user_data) {
 
385
  struct _ShareCBData * data = (struct _ShareCBData *) user_data;
 
386
  GtkWidget * dialog;
 
387
 
 
388
  dialog = ubuntuone_nautilus_share_dialog_construct (data);
 
389
  g_signal_connect (dialog, "close",
 
390
                    G_CALLBACK (ubuntuone_nautilus_share_dialog_closed), data);
 
391
  g_signal_connect (dialog, "response",
 
392
                    G_CALLBACK (ubuntuone_nautilus_share_dialog_response), data);
 
393
 
 
394
  gtk_widget_show (dialog);
 
395
}
 
396
 
 
397
 
 
398
/* Menu provider */
 
399
static GList * ubuntuone_nautilus_get_menu_items (NautilusMenuProvider * provider,
 
400
                                                   GtkWidget * window,
 
401
                                                   GList * files) {
 
402
  UbuntuOneNautilus * uon;
 
403
  NautilusFileInfo * file;
 
404
  GList * items = NULL;
 
405
  gchar * path;
 
406
  gchar * shared;
 
407
  gchar * myfiles;
 
408
  struct _ShareCBData * share_cb_data;
 
409
 
 
410
  if (g_list_length (files) != 1)
 
411
    return NULL;
 
412
 
 
413
  uon = UBUNTUONE_NAUTILUS (provider);
 
414
 
 
415
  file = g_list_nth_data (files, 0);
 
416
  path = g_filename_from_uri (nautilus_file_info_get_uri (file), NULL, NULL);
 
417
 
 
418
  shared = g_build_filename (uon->managed, "Shared with Me", NULL);
 
419
  myfiles = g_build_filename (uon->managed, "My Files", NULL);
 
420
 
 
421
  if (!ubuntuone_is_storagefs (uon, path))
 
422
    goto done;
 
423
 
 
424
  if (strncmp (path, shared, strlen (shared)) == 0)
 
425
    goto done;
 
426
 
 
427
  if (strncmp (path, myfiles, strlen (myfiles)) != 0)
 
428
    goto done;
 
429
 
 
430
  share_cb_data = g_new0 (struct _ShareCBData, 1);
 
431
  share_cb_data->uon = uon;
 
432
  share_cb_data->parent = window;
 
433
  share_cb_data->path = g_strdup (path);
 
434
 
 
435
  if (nautilus_file_info_is_directory (file)) {
 
436
    NautilusMenuItem * item;
 
437
 
 
438
    item = nautilus_menu_item_new ("ubuntuone-share",
 
439
                                   _("Share on Ubuntu One"),
 
440
                                   _("Share this folder on Ubuntu One"),
 
441
                                   "ubuntuone-client");
 
442
    g_signal_connect (item, "activate",
 
443
                      G_CALLBACK (ubuntuone_nautilus_share_folder),
 
444
                      share_cb_data);
 
445
    items = g_list_prepend (items, item);
 
446
  }
 
447
 
 
448
 done:
 
449
  g_free (myfiles);
 
450
  g_free (shared);
 
451
  g_free (path);
 
452
  return items;
 
453
}
 
454
 
 
455
static GList * ubuntuone_nautilus_get_bg_menu_items (NautilusMenuProvider * provider,
 
456
                                                     GtkWidget * window,
 
457
                                                     NautilusFileInfo * folder) {
 
458
  GList * files = NULL;
 
459
  GList * items = NULL;
 
460
 
 
461
  files = g_list_prepend (files, folder);
 
462
  items = ubuntuone_nautilus_get_menu_items (provider, window, files);
 
463
  files = g_list_remove (files, folder);
 
464
  g_list_free (files);
 
465
 
 
466
  return items;
 
467
}
 
468
 
 
469
static void ubuntuone_nautilus_menu_provider_iface_init (NautilusMenuProviderIface * iface) {
 
470
  iface->get_file_items = ubuntuone_nautilus_get_menu_items;
 
471
  iface->get_background_items = ubuntuone_nautilus_get_bg_menu_items;
 
472
}
 
473
 
 
474
/* GType and nautilus module stuff */
 
475
static GType un_type = 0;
 
476
 
 
477
static void ubuntuone_nautilus_instance_init (UbuntuOneNautilus * uon) {
 
478
  uon->connected = FALSE;
 
479
  uon->uploads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
480
  uon->downloads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
481
  uon->shares = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
482
 
 
483
  /* Magic bag of holding +10:
 
484
   * We store some button widgets in a hash table here, so that we can
 
485
   * update the button's label if there are multiple windows open
 
486
   * This is particularly an issue with spatial mode Nautilus
 
487
   */
 
488
  uon->buttons = g_hash_table_new_full (g_str_hash, g_str_equal,
 
489
                                        g_free, NULL);
 
490
 
 
491
  uon->bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
 
492
  if (!uon->bus) {
 
493
    g_warning ("Failed to get session bus.");
 
494
    return;
 
495
  }
 
496
 
 
497
  uon->u1_proxy = dbus_g_proxy_new_for_name (uon->bus,
 
498
                                             "com.ubuntuone.SyncDaemon",
 
499
                                             "/",
 
500
                                             "com.ubuntuone.SyncDaemon.SyncDaemon");
 
501
  uon->u1_status = dbus_g_proxy_new_for_name (uon->bus,
 
502
                                              "com.ubuntuone.SyncDaemon",
 
503
                                              "/status",
 
504
                                              "com.ubuntuone.SyncDaemon.Status");
 
505
  uon->u1_shares = dbus_g_proxy_new_for_name (uon->bus,
 
506
                                              "com.ubuntuone.SyncDaemon",
 
507
                                              "/shares",
 
508
                                              "com.ubuntuone.SyncDaemon.Shares");
 
509
 
 
510
  dbus_g_proxy_begin_call (uon->u1_proxy, "get_rootdir",
 
511
                           ubuntuone_nautilus_got_root, uon,
 
512
                           NULL, G_TYPE_INVALID);
 
513
  dbus_g_proxy_begin_call (uon->u1_shares, "get_shared",
 
514
                           ubuntuone_nautilus_got_shared, uon,
 
515
                           NULL, G_TYPE_INVALID);
 
516
 
 
517
  dbus_g_proxy_add_signal (uon->u1_status, "StatusChanged",
 
518
                           dbus_g_type_get_map ("GHashTable",
 
519
                                                G_TYPE_STRING,
 
520
                                                G_TYPE_STRING),
 
521
                           G_TYPE_INVALID);
 
522
  dbus_g_proxy_connect_signal (uon->u1_status, "StatusChanged",
 
523
                               G_CALLBACK(ubuntuone_nautilus_status_changed),
 
524
                               uon, NULL);
 
525
 
 
526
  dbus_g_proxy_add_signal (uon->u1_status, "UploadStarted",
 
527
                           G_TYPE_STRING,
 
528
                           G_TYPE_INVALID);
 
529
  dbus_g_proxy_connect_signal (uon->u1_status, "UploadStarted",
 
530
                               G_CALLBACK (ubuntuone_nautilus_upload_started),
 
531
                               uon, NULL);
 
532
  dbus_g_proxy_add_signal (uon->u1_status, "UploadFinished",
 
533
                           G_TYPE_STRING,
 
534
                           G_TYPE_INVALID);
 
535
  dbus_g_proxy_connect_signal (uon->u1_status, "UploadFinished",
 
536
                               G_CALLBACK (ubuntuone_nautilus_upload_finished),
 
537
                               uon, NULL);
 
538
  dbus_g_proxy_add_signal (uon->u1_status, "DownloadStarted",
 
539
                           G_TYPE_STRING,
 
540
                           G_TYPE_INVALID);
 
541
  dbus_g_proxy_connect_signal (uon->u1_status, "DownloadStarted",
 
542
                               G_CALLBACK (ubuntuone_nautilus_download_started),
 
543
                               uon, NULL);
 
544
  dbus_g_proxy_add_signal (uon->u1_status, "DownloadFinished",
 
545
                           G_TYPE_STRING,
 
546
                           G_TYPE_INVALID);
 
547
  dbus_g_proxy_connect_signal (uon->u1_status, "DownloadFinished",
 
548
                               G_CALLBACK (ubuntuone_nautilus_download_finished),
 
549
                               uon, NULL);
 
550
  dbus_g_proxy_add_signal (uon->u1_shares, "ShareCreated",
 
551
                           dbus_g_type_get_map ("GHashTable",
 
552
                                                G_TYPE_STRING,
 
553
                                                G_TYPE_STRING),
 
554
                           G_TYPE_INVALID);
 
555
  dbus_g_proxy_connect_signal (uon->u1_shares, "ShareCreated",
 
556
                               G_CALLBACK (ubuntuone_nautilus_share_created),
 
557
                               uon, NULL);
 
558
}
 
559
 
 
560
static void ubuntuone_nautilus_class_init (UbuntuOneNautilusClass * klass) {
 
561
  parent_class = g_type_class_peek_parent (klass);
 
562
 
 
563
  G_OBJECT_CLASS(klass)->finalize = ubuntuone_nautilus_finalize;
 
564
}
 
565
 
 
566
static void ubuntuone_nautilus_finalize(GObject * object) {
 
567
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS(object);
 
568
  GSList * l;
 
569
 
 
570
  g_object_unref (uon->u1_proxy);
 
571
  g_object_unref (uon->u1_status);
 
572
  g_object_unref (uon->bus);
 
573
 
 
574
  g_hash_table_destroy (uon->uploads);
 
575
  uon->uploads = NULL;
 
576
 
 
577
  g_hash_table_destroy (uon->downloads);
 
578
  uon->downloads = NULL;
 
579
 
 
580
  g_hash_table_destroy (uon->shares);
 
581
  uon->shares = NULL;
 
582
 
 
583
  g_hash_table_destroy (uon->buttons);
 
584
  uon->buttons = NULL;
 
585
}
 
586
 
 
587
static GType ubuntuone_nautilus_get_type (void) {
 
588
  return un_type;
 
589
}
 
590
 
 
591
static void ubuntuone_nautilus_register_type (GTypeModule * module) {
 
592
  static const GTypeInfo info = {
 
593
    sizeof (UbuntuOneNautilusClass),
 
594
    (GBaseInitFunc) NULL,
 
595
    (GBaseFinalizeFunc) NULL,
 
596
    (GClassInitFunc) ubuntuone_nautilus_class_init,
 
597
    NULL,
 
598
    NULL,
 
599
    sizeof (UbuntuOneNautilus),
 
600
    0,
 
601
    (GInstanceInitFunc) ubuntuone_nautilus_instance_init,
 
602
  };
 
603
 
 
604
  static const GInterfaceInfo info_provider_iface_info = {
 
605
    (GInterfaceInitFunc) ubuntuone_nautilus_info_provider_iface_init,
 
606
    NULL,
 
607
    NULL
 
608
  };
 
609
 
 
610
  static const GInterfaceInfo bar_provider_iface_info = {
 
611
    (GInterfaceInitFunc) ubuntuone_nautilus_bar_provider_iface_init,
 
612
    NULL,
 
613
    NULL
 
614
  };
 
615
 
 
616
  static const GInterfaceInfo menu_provider_iface_info = {
 
617
    (GInterfaceInitFunc) ubuntuone_nautilus_menu_provider_iface_init,
 
618
    NULL,
 
619
    NULL
 
620
  };
 
621
 
 
622
  un_type = g_type_module_register_type (module, 
 
623
                                         G_TYPE_OBJECT,
 
624
                                         "UbuntuOneNautilus",
 
625
                                         &info, 0);
 
626
  
 
627
  g_type_module_add_interface (module,
 
628
                               un_type,
 
629
                               NAUTILUS_TYPE_INFO_PROVIDER,
 
630
                               &info_provider_iface_info);
 
631
 
 
632
  g_type_module_add_interface (module,
 
633
                               un_type,
 
634
                               NAUTILUS_TYPE_LOCATION_WIDGET_PROVIDER,
 
635
                               &bar_provider_iface_info);
 
636
 
 
637
  /* XXX Need to sign a request via DBus */
 
638
#if 0
 
639
  g_type_module_add_interface (module,
 
640
                               un_type,
 
641
                               NAUTILUS_TYPE_MENU_PROVIDER,
 
642
                               &menu_provider_iface_info);
 
643
#endif
 
644
}
 
645
 
 
646
 
 
647
/* DBus signal handlers and async method call handlers */
 
648
static void ubuntuone_nautilus_share_metadata (DBusGProxy * proxy,
 
649
                                               DBusGProxyCall * call_id,
 
650
                                               gpointer user_data) {
 
651
  struct _SharePostData * data = (struct _SharePostData *) user_data;
 
652
  GHashTable * hash;
 
653
  GError * error = NULL;
 
654
  gchar * form_data;
 
655
  gchar * node;
 
656
 
 
657
  if (!dbus_g_proxy_end_call (proxy, call_id, &error,
 
658
                              dbus_g_type_get_map ("GHashTable",
 
659
                                                   G_TYPE_STRING,
 
660
                                                   G_TYPE_STRING), &hash,
 
661
                              G_TYPE_INVALID)) {
 
662
    g_warning ("ERROR: %s", error->message);
 
663
    goto share_done;
 
664
  }
 
665
  node = g_hash_table_lookup (hash, "node_id");
 
666
 
 
667
  /* Need to call a to-be-implemented DBus method on syncdaemon here */
 
668
 
 
669
 share_done:
 
670
  __share_post_data_free (data);
 
671
}
 
672
 
 
673
static void ubuntuone_nautilus_state_toggled (DBusGProxy * proxy,
 
674
                                              DBusGProxyCall * call_id,
 
675
                                              gpointer user_data) {
 
676
  dbus_g_proxy_end_call (proxy, call_id, NULL, G_TYPE_INVALID);
 
677
}
 
678
 
 
679
static void ubuntuone_nautilus_got_root (DBusGProxy * proxy,
 
680
                                         DBusGProxyCall * call_id,
 
681
                                         gpointer user_data) {
 
682
  UbuntuOneNautilus * uon;
 
683
  gchar * managed;
 
684
  GError * error = NULL;
 
685
 
 
686
  if (!dbus_g_proxy_end_call (proxy, call_id, &error,
 
687
                              G_TYPE_STRING, &managed,
 
688
                              G_TYPE_INVALID)) {
 
689
    g_warning ("ERROR: %s", error->message);
 
690
    return;
 
691
  }
 
692
 
 
693
  uon = UBUNTUONE_NAUTILUS (user_data);
 
694
 
 
695
  uon->managed = g_strdup (managed);
 
696
  g_free (managed);
 
697
}
 
698
 
 
699
static void ubuntuone_nautilus_got_shared (DBusGProxy * proxy,
 
700
                                           DBusGProxyCall * call_id,
 
701
                                           gpointer user_data) {
 
702
  UbuntuOneNautilus * uon;
 
703
  GSList * data, * l;
 
704
  GError * error = NULL;
 
705
 
 
706
  if (!dbus_g_proxy_end_call (proxy, call_id, &error,
 
707
                              dbus_g_type_get_collection ("GSList",
 
708
                                                          dbus_g_type_get_map
 
709
                                                          ("GHashTable",
 
710
                                                           G_TYPE_STRING,
 
711
                                                           G_TYPE_STRING)),
 
712
                              &data,
 
713
                              G_TYPE_INVALID)) {
 
714
    g_warning ("ERROR: %s", error->message);
 
715
    return;
 
716
  }
 
717
 
 
718
  uon = UBUNTUONE_NAUTILUS (user_data);
 
719
  for (l = data; l != NULL && l->data != NULL; l = l->next) {
 
720
    GHashTable * hash = l->data;
 
721
    ubuntuone_nautilus_share_created (proxy, hash, user_data);
 
722
    data = g_slist_remove (data, hash);
 
723
  }
 
724
  g_slist_free (data);
 
725
}
 
726
 
 
727
static void ubuntuone_nautilus_button_foreach (gpointer key,
 
728
                                               gpointer value,
 
729
                                               gpointer user_data) {
 
730
  const char * label = (const char *) user_data;
 
731
  GtkButton * button = GTK_BUTTON (value);
 
732
 
 
733
  gtk_button_set_label (button, label);
 
734
}
 
735
 
 
736
static void ubuntuone_nautilus_status_changed (DBusGProxy * proxy,
 
737
                                               GHashTable * hash,
 
738
                                               gpointer user_data) {
 
739
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
740
  gchar * status;
 
741
  gchar * is_online;
 
742
  gchar * is_connected;
 
743
 
 
744
  is_online = g_hash_table_lookup (hash, "is_online");
 
745
  is_connected = g_hash_table_lookup (hash, "is_connected");
 
746
  status = g_hash_table_lookup (hash, "name");
 
747
 
 
748
  if (is_online[0] == '\0' || is_connected[0] == '\0' ||
 
749
      strncmp (status, "INIT", 4) == 0||
 
750
      strncmp (status, "READY", 5) == 0) {
 
751
    uon->connected = FALSE;
 
752
    g_hash_table_foreach (uon->buttons,
 
753
                          (GHFunc) ubuntuone_nautilus_button_foreach,
 
754
                          _("Connect"));
 
755
  } else {
 
756
    uon->connected = TRUE;
 
757
    g_hash_table_foreach (uon->buttons,
 
758
                          (GHFunc) ubuntuone_nautilus_button_foreach,
 
759
                          _("Disconnect"));
 
760
  }
 
761
}
 
762
 
 
763
static void ubuntuone_nautilus_upload_started (DBusGProxy * proxy,
 
764
                                               gchar * path,
 
765
                                               gpointer user_data) {
 
766
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
767
 
 
768
  if (!g_hash_table_lookup (uon->uploads, path)) {
 
769
    gchar *new_path = g_strdup (path);
 
770
    g_hash_table_insert (uon->uploads, new_path, new_path);
 
771
    utime (path, NULL);
 
772
  }
 
773
}
 
774
 
 
775
static void ubuntuone_nautilus_upload_finished (DBusGProxy * proxy,
 
776
                                                gchar * path,
 
777
                                                gpointer user_data) {
 
778
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
779
 
 
780
  g_hash_table_remove (uon->uploads, path);
 
781
  utime (path, NULL);
 
782
}
 
783
 
 
784
static void ubuntuone_nautilus_download_started (DBusGProxy * proxy,
 
785
                                                 gchar * path,
 
786
                                                 gpointer user_data) {
 
787
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
788
  gchar * partial;
 
789
  const gchar * usepath;
 
790
  int fd;
 
791
 
 
792
  partial = g_strconcat (path, ".partial", NULL);
 
793
  if (g_file_test (path, G_FILE_TEST_IS_DIR))
 
794
    usepath = path;
 
795
  else
 
796
    usepath = partial;
 
797
 
 
798
  if (!g_hash_table_lookup (uon->uploads, usepath)) {
 
799
    gchar *new_path = g_strdup (usepath);
 
800
    g_hash_table_insert (uon->downloads, new_path, new_path);
 
801
    if (!g_file_test (usepath, G_FILE_TEST_EXISTS)) {
 
802
      fd = open (usepath, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
 
803
                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
 
804
      close (fd);
 
805
    }
 
806
    utime (usepath, NULL);
 
807
  }
 
808
  g_free (partial);
 
809
}
 
810
 
 
811
static void ubuntuone_nautilus_download_finished (DBusGProxy * proxy,
 
812
                                                  gchar * path,
 
813
                                                  gpointer user_data) {
 
814
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
815
  gchar * partial;
 
816
  const gchar * usepath;
 
817
 
 
818
  partial = g_strconcat (path, ".partial", NULL);
 
819
  if (g_file_test (path, G_FILE_TEST_IS_DIR))
 
820
    usepath = path;
 
821
  else
 
822
    usepath = partial;
 
823
 
 
824
  g_hash_table_remove (uon->downloads, usepath);
 
825
  utime (usepath, NULL);
 
826
 
 
827
  g_free (partial);
 
828
}
 
829
 
 
830
static void ubuntuone_nautilus_share_created (DBusGProxy * proxy,
 
831
                                              GHashTable * hash,
 
832
                                              gpointer user_data) {
 
833
  UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS (user_data);
 
834
  gchar * path;
 
835
 
 
836
  path = g_hash_table_lookup (hash, "path");
 
837
  if (!g_hash_table_lookup (uon->shares, path)) {
 
838
    gchar *new_share = g_strdup (path);
 
839
    g_hash_table_insert (uon->shares, new_share, new_share);
 
840
  }
 
841
}
 
842
 
 
843
/* Required Nautilus module handling methods */
 
844
void nautilus_module_initialize (GTypeModule * module) {
 
845
#ifdef ENABLE_NLS
 
846
  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 
847
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
848
  textdomain (GETTEXT_PACKAGE);
 
849
#endif
 
850
 
 
851
  ubuntuone_nautilus_register_type (module);
 
852
}
 
853
 
 
854
void nautilus_module_shutdown (void) {
 
855
}
 
856
 
 
857
 
 
858
void nautilus_module_list_types (const GType ** types,
 
859
                                 int * num_types) {
 
860
  static GType type_list[1];
 
861
  
 
862
  type_list[0] = UBUNTUONE_TYPE_NAUTILUS;
 
863
 
 
864
  *types = type_list;
 
865
  *num_types = 1;
 
866
}