1 | /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ |
---|
2 | /* e-storage.c |
---|
3 | * |
---|
4 | * Copyright (C) 2000, 2001 Ximian, Inc. |
---|
5 | * |
---|
6 | * This program is free software; you can redistribute it and/or |
---|
7 | * modify it under the terms of version 2 of the GNU General Public |
---|
8 | * License as published by the Free Software Foundation. |
---|
9 | * |
---|
10 | * This program is distributed in the hope that it will be useful, |
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
13 | * General Public License for more details. |
---|
14 | * |
---|
15 | * You should have received a copy of the GNU General Public |
---|
16 | * License along with this program; if not, write to the |
---|
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
18 | * Boston, MA 02111-1307, USA. |
---|
19 | * |
---|
20 | * Author: Ettore Perazzoli |
---|
21 | */ |
---|
22 | |
---|
23 | /* FIXME: The EFolderTree is kept both in the EStorage and the |
---|
24 | * EvolutionStorage. Bad design. |
---|
25 | */ |
---|
26 | |
---|
27 | #ifdef HAVE_CONFIG_H |
---|
28 | #include <config.h> |
---|
29 | #endif |
---|
30 | |
---|
31 | #include "e-storage.h" |
---|
32 | |
---|
33 | #include "e-folder-tree.h" |
---|
34 | #include "e-shell-constants.h" |
---|
35 | |
---|
36 | #include <gtk/gtkobject.h> |
---|
37 | #include <gtk/gtksignal.h> |
---|
38 | |
---|
39 | #include <libgnome/gnome-defs.h> |
---|
40 | #include <libgnome/gnome-i18n.h> |
---|
41 | #include <gal/util/e-util.h> |
---|
42 | |
---|
43 | |
---|
44 | #define PARENT_TYPE GTK_TYPE_OBJECT |
---|
45 | static GtkObjectClass *parent_class = NULL; |
---|
46 | |
---|
47 | #define ES_CLASS(obj) \ |
---|
48 | E_STORAGE_CLASS (GTK_OBJECT (obj)->klass) |
---|
49 | |
---|
50 | struct _EStoragePrivate { |
---|
51 | /* The set of folders we have in this storage. */ |
---|
52 | EFolderTree *folder_tree; |
---|
53 | |
---|
54 | /* The pseudofolders representing un-filled-in subtrees */ |
---|
55 | GHashTable *pseudofolders; |
---|
56 | |
---|
57 | /* Internal name of the storage */ |
---|
58 | char *name; |
---|
59 | }; |
---|
60 | |
---|
61 | enum { |
---|
62 | NEW_FOLDER, |
---|
63 | UPDATED_FOLDER, |
---|
64 | REMOVED_FOLDER, |
---|
65 | CLOSE_FOLDER, |
---|
66 | LAST_SIGNAL |
---|
67 | }; |
---|
68 | |
---|
69 | static guint signals[LAST_SIGNAL] = { 0 }; |
---|
70 | |
---|
71 | |
---|
72 | /* Destroy notification function for the folders in the tree. */ |
---|
73 | |
---|
74 | static void |
---|
75 | folder_destroy_notify (EFolderTree *tree, |
---|
76 | const char *path, |
---|
77 | void *data, |
---|
78 | void *closure) |
---|
79 | { |
---|
80 | EFolder *e_folder; |
---|
81 | |
---|
82 | if (data == NULL) { |
---|
83 | /* The root folder has no EFolder associated to it. */ |
---|
84 | return; |
---|
85 | } |
---|
86 | |
---|
87 | e_folder = E_FOLDER (data); |
---|
88 | gtk_object_unref (GTK_OBJECT (e_folder)); |
---|
89 | } |
---|
90 | |
---|
91 | |
---|
92 | /* Signal callbacks for the EFolders. */ |
---|
93 | |
---|
94 | static void |
---|
95 | folder_changed_cb (EFolder *folder, |
---|
96 | void *data) |
---|
97 | { |
---|
98 | EStorage *storage; |
---|
99 | EStoragePrivate *priv; |
---|
100 | const char *path, *p; |
---|
101 | gboolean highlight; |
---|
102 | |
---|
103 | g_assert (E_IS_STORAGE (data)); |
---|
104 | |
---|
105 | storage = E_STORAGE (data); |
---|
106 | priv = storage->priv; |
---|
107 | |
---|
108 | path = e_folder_tree_get_path_for_data (priv->folder_tree, folder); |
---|
109 | g_assert (path != NULL); |
---|
110 | |
---|
111 | gtk_signal_emit (GTK_OBJECT (storage), signals[UPDATED_FOLDER], path); |
---|
112 | |
---|
113 | highlight = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (folder), "last_highlight")); |
---|
114 | if (highlight != e_folder_get_highlighted (folder)) { |
---|
115 | highlight = !highlight; |
---|
116 | gtk_object_set_data (GTK_OBJECT (folder), "last_highlight", |
---|
117 | GINT_TO_POINTER (highlight)); |
---|
118 | p = strrchr (path, '/'); |
---|
119 | if (p && p != path) { |
---|
120 | char *name; |
---|
121 | |
---|
122 | name = g_strndup (path, p - path); |
---|
123 | folder = e_folder_tree_get_folder (priv->folder_tree, name); |
---|
124 | g_free (name); |
---|
125 | if (folder) |
---|
126 | e_folder_set_child_highlight (folder, highlight); |
---|
127 | } |
---|
128 | } |
---|
129 | } |
---|
130 | |
---|
131 | |
---|
132 | /* GtkObject methods. */ |
---|
133 | |
---|
134 | static void |
---|
135 | free_folder (gpointer path, gpointer folder, gpointer user_data) |
---|
136 | { |
---|
137 | g_free (path); |
---|
138 | /* folders will have been freed by e_folder_tree_destroy */ |
---|
139 | } |
---|
140 | |
---|
141 | static void |
---|
142 | destroy (GtkObject *object) |
---|
143 | { |
---|
144 | EStorage *storage; |
---|
145 | EStoragePrivate *priv; |
---|
146 | |
---|
147 | storage = E_STORAGE (object); |
---|
148 | priv = storage->priv; |
---|
149 | |
---|
150 | if (priv->folder_tree != NULL) |
---|
151 | e_folder_tree_destroy (priv->folder_tree); |
---|
152 | if (priv->pseudofolders) { |
---|
153 | g_hash_table_foreach (priv->pseudofolders, free_folder, NULL); |
---|
154 | g_hash_table_destroy (priv->pseudofolders); |
---|
155 | } |
---|
156 | |
---|
157 | g_free (priv->name); |
---|
158 | |
---|
159 | (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | /* EStorage methods. */ |
---|
164 | |
---|
165 | static GList * |
---|
166 | impl_get_subfolder_paths (EStorage *storage, |
---|
167 | const char *path) |
---|
168 | { |
---|
169 | EStoragePrivate *priv; |
---|
170 | |
---|
171 | priv = storage->priv; |
---|
172 | |
---|
173 | return e_folder_tree_get_subfolders (priv->folder_tree, path); |
---|
174 | } |
---|
175 | |
---|
176 | static EFolder * |
---|
177 | impl_get_folder (EStorage *storage, |
---|
178 | const char *path) |
---|
179 | { |
---|
180 | EStoragePrivate *priv; |
---|
181 | EFolder *e_folder; |
---|
182 | |
---|
183 | priv = storage->priv; |
---|
184 | |
---|
185 | e_folder = (EFolder *) e_folder_tree_get_folder (priv->folder_tree, path); |
---|
186 | |
---|
187 | return e_folder; |
---|
188 | } |
---|
189 | |
---|
190 | static const char * |
---|
191 | impl_get_name (EStorage *storage) |
---|
192 | { |
---|
193 | return storage->priv->name; |
---|
194 | } |
---|
195 | |
---|
196 | static void |
---|
197 | impl_async_create_folder (EStorage *storage, |
---|
198 | const char *path, |
---|
199 | const char *type, |
---|
200 | const char *description, |
---|
201 | EStorageResultCallback callback, |
---|
202 | void *data) |
---|
203 | { |
---|
204 | (* callback) (storage, E_STORAGE_NOTIMPLEMENTED, data); |
---|
205 | } |
---|
206 | |
---|
207 | static void |
---|
208 | impl_async_remove_folder (EStorage *storage, |
---|
209 | const char *path, |
---|
210 | EStorageResultCallback callback, |
---|
211 | void *data) |
---|
212 | { |
---|
213 | (* callback) (storage, E_STORAGE_NOTIMPLEMENTED, data); |
---|
214 | } |
---|
215 | |
---|
216 | static void |
---|
217 | impl_async_xfer_folder (EStorage *storage, |
---|
218 | const char *source_path, |
---|
219 | const char *destination_path, |
---|
220 | gboolean remove_source, |
---|
221 | EStorageResultCallback callback, |
---|
222 | void *data) |
---|
223 | { |
---|
224 | (* callback) (storage, E_STORAGE_NOTIMPLEMENTED, data); |
---|
225 | } |
---|
226 | |
---|
227 | static void |
---|
228 | impl_async_open_folder (EStorage *storage, |
---|
229 | const char *path) |
---|
230 | { |
---|
231 | ; |
---|
232 | } |
---|
233 | |
---|
234 | static gboolean |
---|
235 | impl_supports_shared_folders (EStorage *storage) |
---|
236 | { |
---|
237 | return FALSE; |
---|
238 | } |
---|
239 | |
---|
240 | static void |
---|
241 | impl_async_discover_shared_folder (EStorage *storage, |
---|
242 | const char *owner, |
---|
243 | const char *folder_name, |
---|
244 | EStorageDiscoveryCallback callback, |
---|
245 | void *data) |
---|
246 | { |
---|
247 | (* callback) (storage, E_STORAGE_NOTIMPLEMENTED, NULL, data); |
---|
248 | } |
---|
249 | |
---|
250 | static void |
---|
251 | impl_async_remove_shared_folder (EStorage *storage, |
---|
252 | const char *path, |
---|
253 | EStorageResultCallback callback, |
---|
254 | void *data) |
---|
255 | { |
---|
256 | (* callback) (storage, E_STORAGE_NOTIMPLEMENTED, data); |
---|
257 | } |
---|
258 | |
---|
259 | |
---|
260 | /* Initialization. */ |
---|
261 | |
---|
262 | static void |
---|
263 | class_init (EStorageClass *class) |
---|
264 | { |
---|
265 | GtkObjectClass *object_class; |
---|
266 | |
---|
267 | object_class = GTK_OBJECT_CLASS (class); |
---|
268 | parent_class = gtk_type_class (gtk_object_get_type ()); |
---|
269 | |
---|
270 | object_class->destroy = destroy; |
---|
271 | |
---|
272 | class->get_subfolder_paths = impl_get_subfolder_paths; |
---|
273 | class->get_folder = impl_get_folder; |
---|
274 | class->get_name = impl_get_name; |
---|
275 | class->async_create_folder = impl_async_create_folder; |
---|
276 | class->async_remove_folder = impl_async_remove_folder; |
---|
277 | class->async_xfer_folder = impl_async_xfer_folder; |
---|
278 | class->async_open_folder = impl_async_open_folder; |
---|
279 | |
---|
280 | class->supports_shared_folders = impl_supports_shared_folders; |
---|
281 | class->async_discover_shared_folder = impl_async_discover_shared_folder; |
---|
282 | class->async_remove_shared_folder = impl_async_remove_shared_folder; |
---|
283 | |
---|
284 | signals[NEW_FOLDER] = |
---|
285 | gtk_signal_new ("new_folder", |
---|
286 | GTK_RUN_FIRST, |
---|
287 | object_class->type, |
---|
288 | GTK_SIGNAL_OFFSET (EStorageClass, new_folder), |
---|
289 | gtk_marshal_NONE__STRING, |
---|
290 | GTK_TYPE_NONE, 1, |
---|
291 | GTK_TYPE_STRING); |
---|
292 | signals[UPDATED_FOLDER] = |
---|
293 | gtk_signal_new ("updated_folder", |
---|
294 | GTK_RUN_FIRST, |
---|
295 | object_class->type, |
---|
296 | GTK_SIGNAL_OFFSET (EStorageClass, updated_folder), |
---|
297 | gtk_marshal_NONE__STRING, |
---|
298 | GTK_TYPE_NONE, 1, |
---|
299 | GTK_TYPE_STRING); |
---|
300 | signals[REMOVED_FOLDER] = |
---|
301 | gtk_signal_new ("removed_folder", |
---|
302 | GTK_RUN_FIRST, |
---|
303 | object_class->type, |
---|
304 | GTK_SIGNAL_OFFSET (EStorageClass, removed_folder), |
---|
305 | gtk_marshal_NONE__STRING, |
---|
306 | GTK_TYPE_NONE, 1, |
---|
307 | GTK_TYPE_STRING); |
---|
308 | signals[CLOSE_FOLDER] = |
---|
309 | gtk_signal_new ("close_folder", |
---|
310 | GTK_RUN_FIRST, |
---|
311 | object_class->type, |
---|
312 | GTK_SIGNAL_OFFSET (EStorageClass, close_folder), |
---|
313 | gtk_marshal_NONE__STRING, |
---|
314 | GTK_TYPE_NONE, 1, |
---|
315 | GTK_TYPE_STRING); |
---|
316 | |
---|
317 | gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); |
---|
318 | } |
---|
319 | |
---|
320 | static void |
---|
321 | init (EStorage *storage) |
---|
322 | { |
---|
323 | EStoragePrivate *priv; |
---|
324 | |
---|
325 | priv = g_new (EStoragePrivate, 1); |
---|
326 | |
---|
327 | priv->folder_tree = e_folder_tree_new (folder_destroy_notify, NULL); |
---|
328 | priv->pseudofolders = g_hash_table_new (g_str_hash, g_str_equal); |
---|
329 | priv->name = NULL; |
---|
330 | |
---|
331 | storage->priv = priv; |
---|
332 | } |
---|
333 | |
---|
334 | |
---|
335 | /* Creation. */ |
---|
336 | |
---|
337 | void |
---|
338 | e_storage_construct (EStorage *storage, |
---|
339 | const char *name, |
---|
340 | EFolder *root_folder) |
---|
341 | { |
---|
342 | EStoragePrivate *priv; |
---|
343 | |
---|
344 | g_return_if_fail (storage != NULL); |
---|
345 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
346 | |
---|
347 | priv = storage->priv; |
---|
348 | |
---|
349 | priv->name = g_strdup (name); |
---|
350 | |
---|
351 | e_storage_new_folder (storage, "/", root_folder); |
---|
352 | |
---|
353 | GTK_OBJECT_UNSET_FLAGS (GTK_OBJECT (storage), GTK_FLOATING); |
---|
354 | } |
---|
355 | |
---|
356 | EStorage * |
---|
357 | e_storage_new (const char *name, |
---|
358 | EFolder *root_folder) |
---|
359 | { |
---|
360 | EStorage *new; |
---|
361 | |
---|
362 | new = gtk_type_new (e_storage_get_type ()); |
---|
363 | |
---|
364 | e_storage_construct (new, name, root_folder); |
---|
365 | |
---|
366 | return new; |
---|
367 | } |
---|
368 | |
---|
369 | |
---|
370 | gboolean |
---|
371 | e_storage_path_is_absolute (const char *path) |
---|
372 | { |
---|
373 | g_return_val_if_fail (path != NULL, FALSE); |
---|
374 | |
---|
375 | return *path == E_PATH_SEPARATOR; |
---|
376 | } |
---|
377 | |
---|
378 | gboolean |
---|
379 | e_storage_path_is_relative (const char *path) |
---|
380 | { |
---|
381 | g_return_val_if_fail (path != NULL, FALSE); |
---|
382 | |
---|
383 | return *path != E_PATH_SEPARATOR; |
---|
384 | } |
---|
385 | |
---|
386 | |
---|
387 | GList * |
---|
388 | e_storage_get_subfolder_paths (EStorage *storage, |
---|
389 | const char *path) |
---|
390 | { |
---|
391 | g_return_val_if_fail (storage != NULL, NULL); |
---|
392 | g_return_val_if_fail (E_IS_STORAGE (storage), NULL); |
---|
393 | g_return_val_if_fail (path != NULL, NULL); |
---|
394 | g_return_val_if_fail (g_path_is_absolute (path), NULL); |
---|
395 | |
---|
396 | return (* ES_CLASS (storage)->get_subfolder_paths) (storage, path); |
---|
397 | } |
---|
398 | |
---|
399 | EFolder * |
---|
400 | e_storage_get_folder (EStorage *storage, |
---|
401 | const char *path) |
---|
402 | { |
---|
403 | g_return_val_if_fail (storage != NULL, NULL); |
---|
404 | g_return_val_if_fail (E_IS_STORAGE (storage), NULL); |
---|
405 | g_return_val_if_fail (path != NULL, NULL); |
---|
406 | g_return_val_if_fail (e_storage_path_is_absolute (path), NULL); |
---|
407 | |
---|
408 | return (* ES_CLASS (storage)->get_folder) (storage, path); |
---|
409 | } |
---|
410 | |
---|
411 | const char * |
---|
412 | e_storage_get_name (EStorage *storage) |
---|
413 | { |
---|
414 | g_return_val_if_fail (storage != NULL, NULL); |
---|
415 | g_return_val_if_fail (E_IS_STORAGE (storage), NULL); |
---|
416 | |
---|
417 | return (* ES_CLASS (storage)->get_name) (storage); |
---|
418 | } |
---|
419 | |
---|
420 | |
---|
421 | /* Folder operations. */ |
---|
422 | |
---|
423 | void |
---|
424 | e_storage_async_create_folder (EStorage *storage, |
---|
425 | const char *path, |
---|
426 | const char *type, |
---|
427 | const char *description, |
---|
428 | EStorageResultCallback callback, |
---|
429 | void *data) |
---|
430 | { |
---|
431 | g_return_if_fail (storage != NULL); |
---|
432 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
433 | g_return_if_fail (path != NULL); |
---|
434 | g_return_if_fail (g_path_is_absolute (path)); |
---|
435 | g_return_if_fail (type != NULL); |
---|
436 | g_return_if_fail (callback != NULL); |
---|
437 | |
---|
438 | (* ES_CLASS (storage)->async_create_folder) (storage, path, type, description, callback, data); |
---|
439 | } |
---|
440 | |
---|
441 | void |
---|
442 | e_storage_async_remove_folder (EStorage *storage, |
---|
443 | const char *path, |
---|
444 | EStorageResultCallback callback, |
---|
445 | void *data) |
---|
446 | { |
---|
447 | g_return_if_fail (storage != NULL); |
---|
448 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
449 | g_return_if_fail (path != NULL); |
---|
450 | g_return_if_fail (g_path_is_absolute (path)); |
---|
451 | g_return_if_fail (callback != NULL); |
---|
452 | |
---|
453 | (* ES_CLASS (storage)->async_remove_folder) (storage, path, callback, data); |
---|
454 | } |
---|
455 | |
---|
456 | void |
---|
457 | e_storage_async_xfer_folder (EStorage *storage, |
---|
458 | const char *source_path, |
---|
459 | const char *destination_path, |
---|
460 | const gboolean remove_source, |
---|
461 | EStorageResultCallback callback, |
---|
462 | void *data) |
---|
463 | { |
---|
464 | g_return_if_fail (storage != NULL); |
---|
465 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
466 | g_return_if_fail (source_path != NULL); |
---|
467 | g_return_if_fail (g_path_is_absolute (source_path)); |
---|
468 | g_return_if_fail (destination_path != NULL); |
---|
469 | g_return_if_fail (g_path_is_absolute (destination_path)); |
---|
470 | |
---|
471 | if (strcmp (source_path, destination_path) == 0) { |
---|
472 | (* callback) (storage, E_STORAGE_OK, data); |
---|
473 | return; |
---|
474 | } |
---|
475 | |
---|
476 | if (remove_source) { |
---|
477 | int destination_len; |
---|
478 | int source_len; |
---|
479 | |
---|
480 | source_len = strlen (source_path); |
---|
481 | destination_len = strlen (destination_path); |
---|
482 | |
---|
483 | if (source_len < destination_len |
---|
484 | && destination_path[source_len] == E_PATH_SEPARATOR |
---|
485 | && strncmp (destination_path, source_path, source_len) == 0) { |
---|
486 | (* callback) (storage, E_STORAGE_CANTMOVETODESCENDANT, data); |
---|
487 | return; |
---|
488 | } |
---|
489 | } |
---|
490 | |
---|
491 | (* ES_CLASS (storage)->async_xfer_folder) (storage, source_path, destination_path, remove_source, callback, data); |
---|
492 | } |
---|
493 | |
---|
494 | void |
---|
495 | e_storage_async_open_folder (EStorage *storage, |
---|
496 | const char *path) |
---|
497 | { |
---|
498 | g_return_if_fail (storage != NULL); |
---|
499 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
500 | g_return_if_fail (path != NULL); |
---|
501 | g_return_if_fail (g_path_is_absolute (path)); |
---|
502 | |
---|
503 | if (g_hash_table_lookup (storage->priv->pseudofolders, path) == NULL) |
---|
504 | return; |
---|
505 | |
---|
506 | (* ES_CLASS (storage)->async_open_folder) (storage, path); |
---|
507 | } |
---|
508 | |
---|
509 | |
---|
510 | /* Shared folders. */ |
---|
511 | |
---|
512 | gboolean |
---|
513 | e_storage_supports_shared_folders (EStorage *storage) |
---|
514 | { |
---|
515 | g_return_val_if_fail (storage != NULL, FALSE); |
---|
516 | g_return_val_if_fail (E_IS_STORAGE (storage), FALSE); |
---|
517 | |
---|
518 | return (* ES_CLASS (storage)->supports_shared_folders) (storage); |
---|
519 | } |
---|
520 | |
---|
521 | void |
---|
522 | e_storage_async_discover_shared_folder (EStorage *storage, |
---|
523 | const char *owner, |
---|
524 | const char *folder_name, |
---|
525 | EStorageDiscoveryCallback callback, |
---|
526 | void *data) |
---|
527 | { |
---|
528 | g_return_if_fail (storage != NULL); |
---|
529 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
530 | g_return_if_fail (owner != NULL); |
---|
531 | g_return_if_fail (folder_name != NULL); |
---|
532 | |
---|
533 | (* ES_CLASS (storage)->async_discover_shared_folder) (storage, owner, folder_name, callback, data); |
---|
534 | } |
---|
535 | |
---|
536 | void |
---|
537 | e_storage_cancel_discover_shared_folder (EStorage *storage, |
---|
538 | const char *owner, |
---|
539 | const char *folder_name) |
---|
540 | { |
---|
541 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
542 | g_return_if_fail (owner != NULL); |
---|
543 | g_return_if_fail (folder_name != NULL); |
---|
544 | g_return_if_fail (ES_CLASS (storage)->cancel_discover_shared_folder != NULL); |
---|
545 | |
---|
546 | (* ES_CLASS (storage)->cancel_discover_shared_folder) (storage, owner, folder_name); |
---|
547 | } |
---|
548 | |
---|
549 | void |
---|
550 | e_storage_async_remove_shared_folder (EStorage *storage, |
---|
551 | const char *path, |
---|
552 | EStorageResultCallback callback, |
---|
553 | void *data) |
---|
554 | { |
---|
555 | g_return_if_fail (storage != NULL); |
---|
556 | g_return_if_fail (E_IS_STORAGE (storage)); |
---|
557 | g_return_if_fail (path != NULL); |
---|
558 | g_return_if_fail (g_path_is_absolute (path)); |
---|
559 | |
---|
560 | (* ES_CLASS (storage)->async_remove_shared_folder) (storage, path, callback, data); |
---|
561 | } |
---|
562 | |
---|
563 | |
---|
564 | const char * |
---|
565 | e_storage_result_to_string (EStorageResult result) |
---|
566 | { |
---|
567 | switch (result) { |
---|
568 | case E_STORAGE_OK: |
---|
569 | return _("No error"); |
---|
570 | case E_STORAGE_GENERICERROR: |
---|
571 | return _("Generic error"); |
---|
572 | case E_STORAGE_EXISTS: |
---|
573 | return _("A folder with the same name already exists"); |
---|
574 | case E_STORAGE_INVALIDTYPE: |
---|
575 | return _("The specified folder type is not valid"); |
---|
576 | case E_STORAGE_IOERROR: |
---|
577 | return _("I/O error"); |
---|
578 | case E_STORAGE_NOSPACE: |
---|
579 | return _("Not enough space to create the folder"); |
---|
580 | case E_STORAGE_NOTEMPTY: |
---|
581 | return _("The folder is not empty"); |
---|
582 | case E_STORAGE_NOTFOUND: |
---|
583 | return _("The specified folder was not found"); |
---|
584 | case E_STORAGE_NOTIMPLEMENTED: |
---|
585 | return _("Function not implemented in this storage"); |
---|
586 | case E_STORAGE_PERMISSIONDENIED: |
---|
587 | return _("Permission denied"); |
---|
588 | case E_STORAGE_UNSUPPORTEDOPERATION: |
---|
589 | return _("Operation not supported"); |
---|
590 | case E_STORAGE_UNSUPPORTEDTYPE: |
---|
591 | return _("The specified type is not supported in this storage"); |
---|
592 | case E_STORAGE_CANTCHANGESTOCKFOLDER: |
---|
593 | return _("The specified folder cannot be modified or removed"); |
---|
594 | case E_STORAGE_CANTMOVETODESCENDANT: |
---|
595 | return _("Cannot make a folder a child of one of its descendants"); |
---|
596 | case E_STORAGE_INVALIDNAME: |
---|
597 | return _("Cannot create a folder with that name"); |
---|
598 | case E_STORAGE_NOTONLINE: |
---|
599 | return _("This operation cannot be performed in off-line mode"); |
---|
600 | default: |
---|
601 | return _("Unknown error"); |
---|
602 | } |
---|
603 | } |
---|
604 | |
---|
605 | |
---|
606 | /* Public utility functions. */ |
---|
607 | |
---|
608 | struct _GetPathForPhysicalUriForeachData { |
---|
609 | const char *physical_uri; |
---|
610 | char *retval; |
---|
611 | }; |
---|
612 | typedef struct _GetPathForPhysicalUriForeachData GetPathForPhysicalUriForeachData; |
---|
613 | |
---|
614 | static void |
---|
615 | get_path_for_physical_uri_foreach (EFolderTree *folder_tree, |
---|
616 | const char *path, |
---|
617 | void *path_data, |
---|
618 | void *user_data) |
---|
619 | { |
---|
620 | GetPathForPhysicalUriForeachData *foreach_data; |
---|
621 | const char *physical_uri; |
---|
622 | EFolder *e_folder; |
---|
623 | |
---|
624 | foreach_data = (GetPathForPhysicalUriForeachData *) user_data; |
---|
625 | if (foreach_data->retval != NULL) |
---|
626 | return; |
---|
627 | |
---|
628 | e_folder = (EFolder *) path_data; |
---|
629 | if (e_folder == NULL) |
---|
630 | return; |
---|
631 | |
---|
632 | physical_uri = e_folder_get_physical_uri (e_folder); |
---|
633 | if (physical_uri == NULL) |
---|
634 | return; |
---|
635 | |
---|
636 | if (strcmp (foreach_data->physical_uri, physical_uri) == 0) |
---|
637 | foreach_data->retval = g_strdup (path); |
---|
638 | } |
---|
639 | |
---|
640 | /** |
---|
641 | * e_storage_get_path_for_physical_uri: |
---|
642 | * @storage: A storage |
---|
643 | * @physical_uri: A physical URI |
---|
644 | * |
---|
645 | * Look for the folder having the specified @physical_uri. |
---|
646 | * |
---|
647 | * Return value: The path of the folder having the specified @physical_uri in |
---|
648 | * @storage. If such a folder does not exist, just return NULL. The return |
---|
649 | * value must be freed by the caller. |
---|
650 | **/ |
---|
651 | char * |
---|
652 | e_storage_get_path_for_physical_uri (EStorage *storage, |
---|
653 | const char *physical_uri) |
---|
654 | { |
---|
655 | GetPathForPhysicalUriForeachData foreach_data; |
---|
656 | EStoragePrivate *priv; |
---|
657 | |
---|
658 | g_return_val_if_fail (storage != NULL, NULL); |
---|
659 | g_return_val_if_fail (E_IS_STORAGE (storage), NULL); |
---|
660 | g_return_val_if_fail (physical_uri != NULL, NULL); |
---|
661 | |
---|
662 | priv = storage->priv; |
---|
663 | |
---|
664 | foreach_data.physical_uri = physical_uri; |
---|
665 | foreach_data.retval = NULL; |
---|
666 | |
---|
667 | e_folder_tree_foreach (priv->folder_tree, get_path_for_physical_uri_foreach, &foreach_data); |
---|
668 | |
---|
669 | return foreach_data.retval; |
---|
670 | } |
---|
671 | |
---|
672 | |
---|
673 | /* Protected functions. */ |
---|
674 | |
---|
675 | /* These functions are used by subclasses to add and remove folders from the |
---|
676 | state stored in the storage object. */ |
---|
677 | |
---|
678 | gboolean |
---|
679 | e_storage_new_folder (EStorage *storage, |
---|
680 | const char *path, |
---|
681 | EFolder *e_folder) |
---|
682 | { |
---|
683 | EStoragePrivate *priv; |
---|
684 | char *parent_path, *p; |
---|
685 | gpointer stored_path, pseudofolder; |
---|
686 | |
---|
687 | g_return_val_if_fail (storage != NULL, FALSE); |
---|
688 | g_return_val_if_fail (E_IS_STORAGE (storage), FALSE); |
---|
689 | g_return_val_if_fail (path != NULL, FALSE); |
---|
690 | g_return_val_if_fail (g_path_is_absolute (path), FALSE); |
---|
691 | g_return_val_if_fail (e_folder != NULL, FALSE); |
---|
692 | g_return_val_if_fail (E_IS_FOLDER (e_folder), FALSE); |
---|
693 | |
---|
694 | priv = storage->priv; |
---|
695 | |
---|
696 | if (! e_folder_tree_add (priv->folder_tree, path, e_folder)) |
---|
697 | return FALSE; |
---|
698 | |
---|
699 | p = strrchr (path, '/'); |
---|
700 | if (p && p != path) |
---|
701 | parent_path = g_strndup (path, p - path); |
---|
702 | else |
---|
703 | parent_path = g_strdup ("/"); |
---|
704 | if (g_hash_table_lookup_extended (priv->pseudofolders, parent_path, |
---|
705 | &stored_path, &pseudofolder) && |
---|
706 | pseudofolder != e_folder) { |
---|
707 | g_hash_table_remove (priv->pseudofolders, parent_path); |
---|
708 | g_free (stored_path); |
---|
709 | e_storage_removed_folder (storage, e_folder_get_physical_uri (pseudofolder)); |
---|
710 | } |
---|
711 | g_free (parent_path); |
---|
712 | |
---|
713 | gtk_signal_connect_while_alive (GTK_OBJECT (e_folder), "changed", folder_changed_cb, |
---|
714 | storage, GTK_OBJECT (storage)); |
---|
715 | |
---|
716 | gtk_signal_emit (GTK_OBJECT (storage), signals[NEW_FOLDER], path); |
---|
717 | |
---|
718 | folder_changed_cb (e_folder, storage); |
---|
719 | |
---|
720 | return TRUE; |
---|
721 | } |
---|
722 | |
---|
723 | gboolean |
---|
724 | e_storage_has_subfolders (EStorage *storage, |
---|
725 | const char *path, |
---|
726 | const char *message) |
---|
727 | { |
---|
728 | EStoragePrivate *priv; |
---|
729 | GList *subfolders, *f; |
---|
730 | EFolder *pseudofolder; |
---|
731 | char *pseudofolder_path; |
---|
732 | gboolean retval; |
---|
733 | |
---|
734 | g_return_val_if_fail (storage != NULL, FALSE); |
---|
735 | g_return_val_if_fail (E_IS_STORAGE (storage), FALSE); |
---|
736 | g_return_val_if_fail (path != NULL, FALSE); |
---|
737 | g_return_val_if_fail (g_path_is_absolute (path), FALSE); |
---|
738 | g_return_val_if_fail (message != NULL, FALSE); |
---|
739 | |
---|
740 | priv = storage->priv; |
---|
741 | |
---|
742 | gtk_signal_emit (GTK_OBJECT (storage), signals[CLOSE_FOLDER], path); |
---|
743 | |
---|
744 | if (g_hash_table_lookup (priv->pseudofolders, path)) |
---|
745 | return TRUE; |
---|
746 | |
---|
747 | subfolders = e_folder_tree_get_subfolders (priv->folder_tree, path); |
---|
748 | if (subfolders != NULL) { |
---|
749 | for (f = subfolders; f; f = f->next) |
---|
750 | e_storage_removed_folder (storage, f->data); |
---|
751 | g_list_free (subfolders); |
---|
752 | /* FIXME: close parent */ |
---|
753 | } |
---|
754 | |
---|
755 | pseudofolder = e_folder_new (message, "working", ""); |
---|
756 | if (strcmp (path, "/") == 0) |
---|
757 | pseudofolder_path = g_strdup_printf ("/%s", message); |
---|
758 | else |
---|
759 | pseudofolder_path = g_strdup_printf ("%s/%s", path, message); |
---|
760 | e_folder_set_physical_uri (pseudofolder, pseudofolder_path); |
---|
761 | |
---|
762 | g_hash_table_insert (priv->pseudofolders, g_strdup (path), pseudofolder); |
---|
763 | |
---|
764 | retval = e_storage_new_folder (storage, pseudofolder_path, pseudofolder); |
---|
765 | g_free (pseudofolder_path); |
---|
766 | |
---|
767 | return retval; |
---|
768 | } |
---|
769 | |
---|
770 | gboolean |
---|
771 | e_storage_removed_folder (EStorage *storage, |
---|
772 | const char *path) |
---|
773 | { |
---|
774 | EStoragePrivate *priv; |
---|
775 | EFolder *folder; |
---|
776 | const char *p; |
---|
777 | |
---|
778 | g_return_val_if_fail (storage != NULL, FALSE); |
---|
779 | g_return_val_if_fail (E_IS_STORAGE (storage), FALSE); |
---|
780 | g_return_val_if_fail (path != NULL, FALSE); |
---|
781 | g_return_val_if_fail (g_path_is_absolute (path), FALSE); |
---|
782 | |
---|
783 | priv = storage->priv; |
---|
784 | |
---|
785 | folder = e_folder_tree_get_folder (priv->folder_tree, path); |
---|
786 | if (folder == NULL) |
---|
787 | return FALSE; |
---|
788 | |
---|
789 | p = strrchr (path, '/'); |
---|
790 | if (p != NULL && p != path) { |
---|
791 | EFolder *parent_folder; |
---|
792 | char *parent_path; |
---|
793 | |
---|
794 | parent_path = g_strndup (path, p - path); |
---|
795 | parent_folder = e_folder_tree_get_folder (priv->folder_tree, parent_path); |
---|
796 | |
---|
797 | if (e_folder_get_highlighted (folder)) |
---|
798 | e_folder_set_child_highlight (parent_folder, FALSE); |
---|
799 | |
---|
800 | g_free (parent_path); |
---|
801 | } |
---|
802 | |
---|
803 | gtk_signal_emit (GTK_OBJECT (storage), signals[REMOVED_FOLDER], path); |
---|
804 | |
---|
805 | e_folder_tree_remove (priv->folder_tree, path); |
---|
806 | |
---|
807 | return TRUE; |
---|
808 | } |
---|
809 | |
---|
810 | |
---|
811 | E_MAKE_TYPE (e_storage, "EStorage", EStorage, class_init, init, PARENT_TYPE) |
---|