1 /*
2  *
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10  * for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public License
13  * along with this program; if not, see <http://www.gnu.org/licenses/>.
14  *
15  *
16  * Authors:
17  *		Michael Zucchi <notzed@ximian.com>
18  *
19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20  *
21  */
22 
23 #include "evolution-config.h"
24 
25 #include <glib/gi18n-lib.h>
26 
27 #include "e-file-utils.h"
28 
29 typedef struct _AsyncContext AsyncContext;
30 
31 struct _AsyncContext {
32 	EActivity *activity;
33 	gchar *new_etag;
34 };
35 
36 static void
async_context_free(AsyncContext * context)37 async_context_free (AsyncContext *context)
38 {
39 	if (context->activity != NULL)
40 		g_object_unref (context->activity);
41 
42 	g_free (context->new_etag);
43 
44 	g_slice_free (AsyncContext, context);
45 }
46 
47 static void
file_replace_contents_cb(GFile * file,GAsyncResult * result,GSimpleAsyncResult * simple)48 file_replace_contents_cb (GFile *file,
49                           GAsyncResult *result,
50                           GSimpleAsyncResult *simple)
51 {
52 	AsyncContext *context;
53 	gchar *new_etag = NULL;
54 	GError *error = NULL;
55 
56 	context = g_simple_async_result_get_op_res_gpointer (simple);
57 
58 	g_file_replace_contents_finish (file, result, &new_etag, &error);
59 
60 	if (!e_activity_handle_cancellation (context->activity, error))
61 		e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
62 
63 	if (error == NULL)
64 		context->new_etag = new_etag;
65 	else {
66 		g_warn_if_fail (new_etag == NULL);
67 		g_simple_async_result_take_error (simple, error);
68 	}
69 
70 	g_simple_async_result_complete (simple);
71 
72 	g_object_unref (simple);
73 }
74 
75 /**
76  * e_file_replace_contents_async:
77  * @file: input #GFile
78  * @contents: string of contents to replace the file with
79  * @length: the length of @contents in bytes
80  * @etag: a new entity tag for the @file, or %NULL
81  * @make_backup: %TRUE if a backup should be created
82  * @flags: a set of #GFileCreateFlags
83  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
84  * @user_data: the data to pass to the callback function
85  *
86  * This is a wrapper for g_file_replace_contents_async() that also returns
87  * an #EActivity to track the file operation.  Cancelling the activity will
88  * cancel the file operation.  See g_file_replace_contents_async() for more
89  * details.
90  *
91  * Returns: an #EActivity for the file operation
92  **/
93 EActivity *
e_file_replace_contents_async(GFile * file,const gchar * contents,gsize length,const gchar * etag,gboolean make_backup,GFileCreateFlags flags,GAsyncReadyCallback callback,gpointer user_data)94 e_file_replace_contents_async (GFile *file,
95                                const gchar *contents,
96                                gsize length,
97                                const gchar *etag,
98                                gboolean make_backup,
99                                GFileCreateFlags flags,
100                                GAsyncReadyCallback callback,
101                                gpointer user_data)
102 {
103 	GSimpleAsyncResult *simple;
104 	GCancellable *cancellable;
105 	AsyncContext *context;
106 	const gchar *format;
107 	gchar *description;
108 	gchar *basename;
109 	gchar *filename;
110 	gchar *hostname;
111 	gchar *uri;
112 
113 	g_return_val_if_fail (G_IS_FILE (file), NULL);
114 	g_return_val_if_fail (contents != NULL, NULL);
115 
116 	uri = g_file_get_uri (file);
117 	filename = g_filename_from_uri (uri, &hostname, NULL);
118 	if (filename != NULL)
119 		basename = g_filename_display_basename (filename);
120 	else
121 		basename = g_strdup (_("(Unknown Filename)"));
122 
123 	if (hostname == NULL) {
124 		/* Translators: The string value is the basename of a file. */
125 		format = _("Writing “%s”");
126 		description = g_strdup_printf (format, basename);
127 	} else {
128 		/* Translators: The first string value is the basename of a
129 		 * remote file, the second string value is the hostname. */
130 		format = _("Writing “%s” to %s");
131 		description = g_strdup_printf (format, basename, hostname);
132 	}
133 
134 	cancellable = g_cancellable_new ();
135 
136 	context = g_slice_new0 (AsyncContext);
137 	context->activity = e_activity_new ();
138 
139 	e_activity_set_text (context->activity, description);
140 	e_activity_set_cancellable (context->activity, cancellable);
141 
142 	simple = g_simple_async_result_new (
143 		G_OBJECT (file), callback, user_data,
144 		e_file_replace_contents_async);
145 
146 	g_simple_async_result_set_check_cancellable (simple, cancellable);
147 
148 	g_simple_async_result_set_op_res_gpointer (
149 		simple, context, (GDestroyNotify) async_context_free);
150 
151 	g_file_replace_contents_async (
152 		file, contents, length, etag,
153 		make_backup, flags, cancellable,
154 		(GAsyncReadyCallback) file_replace_contents_cb,
155 		simple);
156 
157 	g_object_unref (cancellable);
158 
159 	g_free (description);
160 	g_free (basename);
161 	g_free (filename);
162 	g_free (hostname);
163 	g_free (uri);
164 
165 	return context->activity;
166 }
167 
168 /**
169  * e_file_replace_contents_finish:
170  * @file: input #GFile
171  * @result: a #GAsyncResult
172  * @new_etag: return location for a new entity tag
173  * @error: return location for a #GError, or %NULL
174  *
175  * Finishes an asynchronous replace of the given @file.  See
176  * e_file_replace_contents_async().  Sets @new_etag to the new entity
177  * tag for the document, if present.  Free it with g_free() when it is
178  * no longer needed.
179  *
180  * Returns: %TRUE on success, %FALSE on failure
181  **/
182 gboolean
e_file_replace_contents_finish(GFile * file,GAsyncResult * result,gchar ** new_etag,GError ** error)183 e_file_replace_contents_finish (GFile *file,
184                                 GAsyncResult *result,
185                                 gchar **new_etag,
186                                 GError **error)
187 {
188 	GSimpleAsyncResult *simple;
189 	AsyncContext *context;
190 
191 	g_return_val_if_fail (G_IS_FILE (file), FALSE);
192 	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
193 
194 	simple = G_SIMPLE_ASYNC_RESULT (result);
195 	context = g_simple_async_result_get_op_res_gpointer (simple);
196 
197 	if (g_simple_async_result_propagate_error (simple, error))
198 		return FALSE;
199 
200 	if (new_etag != NULL)
201 		*new_etag = g_strdup (context->new_etag);
202 
203 	return TRUE;
204 }
205 
206