1 /*
2  * Seahorse
3  *
4  * Copyright (C) 2008 Stefan Walter
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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.
14  * See the GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see
17  * <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include "seahorse-gpgme.h"
23 #include "seahorse-gpgme-data.h"
24 
25 #include <glib.h>
26 #include <gio/gio.h>
27 
28 #include <gpgme.h>
29 
30 #include <sys/types.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 
36 static int
handle_gio_error(GError * err)37 handle_gio_error (GError *err)
38 {
39 	g_return_val_if_fail (err, -1);
40 
41 	if (err->message)
42 		g_message ("%s", err->message);
43 
44 	switch (err->code) {
45 	case G_IO_ERROR_FAILED:
46 		errno = EIO;
47 		break;
48 	case G_IO_ERROR_NOT_FOUND:
49 		errno = ENOENT;
50 		break;
51 	case G_IO_ERROR_EXISTS:
52 		errno = EEXIST;
53 		break;
54 	case G_IO_ERROR_IS_DIRECTORY:
55 		errno = EISDIR;
56 		break;
57 	case G_IO_ERROR_NOT_DIRECTORY:
58 		errno = ENOTDIR;
59 		break;
60 	case G_IO_ERROR_NOT_EMPTY:
61 		errno = ENOTEMPTY;
62 		break;
63 	case G_IO_ERROR_NOT_REGULAR_FILE:
64 	case G_IO_ERROR_NOT_SYMBOLIC_LINK:
65 	case G_IO_ERROR_NOT_MOUNTABLE_FILE:
66 		errno = EBADF;
67 		break;
68 	case G_IO_ERROR_FILENAME_TOO_LONG:
69 		errno = ENAMETOOLONG;
70 		break;
71 	case G_IO_ERROR_INVALID_FILENAME:
72 		errno = EINVAL;
73 		break;
74 	case G_IO_ERROR_TOO_MANY_LINKS:
75 		errno = EMLINK;
76 		break;
77 	case G_IO_ERROR_NO_SPACE:
78 		errno = ENOSPC;
79 		break;
80 	case G_IO_ERROR_INVALID_ARGUMENT:
81 		errno = EINVAL;
82 		break;
83 	case G_IO_ERROR_PERMISSION_DENIED:
84 		errno = EPERM;
85 		break;
86 	case G_IO_ERROR_NOT_SUPPORTED:
87 		errno = ENOTSUP;
88 		break;
89 	case G_IO_ERROR_NOT_MOUNTED:
90 		errno = ENOENT;
91 		break;
92 	case G_IO_ERROR_ALREADY_MOUNTED:
93 		errno = EALREADY;
94 		break;
95 	case G_IO_ERROR_CLOSED:
96 		errno = EBADF;
97 		break;
98 	case G_IO_ERROR_CANCELLED:
99 		errno = EINTR;
100 		break;
101 	case G_IO_ERROR_PENDING:
102 		errno = EALREADY;
103 		break;
104 	case G_IO_ERROR_READ_ONLY:
105 		errno = EACCES;
106 		break;
107 	case G_IO_ERROR_CANT_CREATE_BACKUP:
108 		errno = EIO;
109 		break;
110 	case G_IO_ERROR_WRONG_ETAG:
111 		errno = EACCES;
112 		break;
113 	case G_IO_ERROR_TIMED_OUT:
114 		errno = EIO;
115 		break;
116 	case G_IO_ERROR_WOULD_RECURSE:
117 		errno = ELOOP;
118 		break;
119 	case G_IO_ERROR_BUSY:
120 		errno = EBUSY;
121 		break;
122 	case G_IO_ERROR_WOULD_BLOCK:
123 		errno = EWOULDBLOCK;
124 		break;
125 	case G_IO_ERROR_HOST_NOT_FOUND:
126 		errno = EHOSTDOWN;
127 		break;
128 	case G_IO_ERROR_WOULD_MERGE:
129 		errno = EIO;
130 		break;
131 	case G_IO_ERROR_FAILED_HANDLED:
132 		errno = 0;
133 		break;
134 	default:
135 		errno = EIO;
136 		break;
137 	};
138 
139 	g_error_free (err);
140 	return -1;
141 }
142 
143 /* ----------------------------------------------------------------------------------------
144  * OUTPUT
145  */
146 
147 /* Called by gpgme to read data */
148 static ssize_t
output_write(void * handle,const void * buffer,size_t size)149 output_write(void *handle, const void *buffer, size_t size)
150 {
151 	GOutputStream* output = handle;
152 	GError *err = NULL;
153 	gsize written;
154 
155 	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), -1);
156 
157 	if (!g_output_stream_write_all (output, buffer, size, &written, NULL, &err))
158 		return handle_gio_error (err);
159 
160 	if (!g_output_stream_flush (output, NULL, &err))
161 		return handle_gio_error (err);
162 
163 	return written;
164 }
165 
166 /* Called from gpgme to seek a file */
167 static off_t
output_seek(void * handle,off_t offset,int whence)168 output_seek (void *handle, off_t offset, int whence)
169 {
170 	GSeekable *seek;
171 	GSeekType from = 0;
172 	GError *err = NULL;
173 	GOutputStream* output = handle;
174 
175 	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), -1);
176 
177 	if (!G_IS_SEEKABLE (output)) {
178 		errno = EOPNOTSUPP;
179 		return -1;
180 	}
181 
182 	switch(whence)
183 	{
184 	case SEEK_SET:
185 		from = G_SEEK_SET;
186 		break;
187 	case SEEK_CUR:
188 		from = G_SEEK_CUR;
189 		break;
190 	case SEEK_END:
191 		from = G_SEEK_END;
192 		break;
193 	default:
194 		g_assert_not_reached();
195 		break;
196 	};
197 
198 	seek = G_SEEKABLE (output);
199 	if (!g_seekable_seek (seek, offset, from, NULL, &err))
200 		return handle_gio_error (err);
201 
202 	return offset;
203 }
204 
205 /* Called by gpgme to close a file */
206 static void
output_release(void * handle)207 output_release (void *handle)
208 {
209 	GOutputStream* output = handle;
210 	g_return_if_fail (G_IS_OUTPUT_STREAM (output));
211 
212 	g_object_unref (output);
213 }
214 
215 /* GPGME vfs file operations */
216 static struct gpgme_data_cbs output_cbs =
217 {
218     NULL,
219     output_write,
220     output_seek,
221     output_release
222 };
223 
224 gpgme_data_t
seahorse_gpgme_data_output(GOutputStream * output)225 seahorse_gpgme_data_output (GOutputStream* output)
226 {
227 	gpgme_error_t gerr;
228 	gpgme_data_t ret = NULL;
229 
230 	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
231 
232 	gerr = gpgme_data_new_from_cbs (&ret, &output_cbs, output);
233 	if (!GPG_IS_OK (gerr))
234 		return NULL;
235 
236 	g_object_ref (output);
237 	return ret;
238 }
239 
240 /* -------------------------------------------------------------------------------------
241  * INPUT STREAMS
242  */
243 
244 /* Called by gpgme to read data */
245 static ssize_t
input_read(void * handle,void * buffer,size_t size)246 input_read (void *handle, void *buffer, size_t size)
247 {
248 	GInputStream* input = handle;
249 	GError *err = NULL;
250 	gsize nread;
251 
252 	g_return_val_if_fail (G_IS_INPUT_STREAM (input), -1);
253 
254 	if (!g_input_stream_read_all (input, buffer, size, &nread, NULL, &err))
255 		return handle_gio_error (err);
256 
257 	return nread;
258 }
259 
260 /* Called from gpgme to seek a file */
261 static off_t
input_seek(void * handle,off_t offset,int whence)262 input_seek (void *handle, off_t offset, int whence)
263 {
264 	GSeekable *seek;
265 	GSeekType from = 0;
266 	GError *err = NULL;
267 	GInputStream* input = handle;
268 
269 	g_return_val_if_fail (G_IS_INPUT_STREAM (input), -1);
270 
271 	if (!G_IS_SEEKABLE (input)) {
272 		errno = EOPNOTSUPP;
273 		return -1;
274 	}
275 
276 	switch(whence)
277 	{
278 	case SEEK_SET:
279 		from = G_SEEK_SET;
280 		break;
281 	case SEEK_CUR:
282 		from = G_SEEK_CUR;
283 		break;
284 	case SEEK_END:
285 		from = G_SEEK_END;
286 		break;
287 	default:
288 		g_assert_not_reached();
289 		break;
290 	};
291 
292 	seek = G_SEEKABLE (input);
293 	if (!g_seekable_seek (seek, offset, from, NULL, &err))
294 		return handle_gio_error (err);
295 
296 	return offset;
297 }
298 
299 /* Called by gpgme to close a file */
300 static void
input_release(void * handle)301 input_release (void *handle)
302 {
303 	GInputStream* input = handle;
304 	g_return_if_fail (G_IS_INPUT_STREAM (input));
305 
306 	g_object_unref (input);
307 }
308 
309 /* GPGME vfs file operations */
310 static struct gpgme_data_cbs input_cbs =
311 {
312     input_read,
313     NULL,
314     input_seek,
315     input_release
316 };
317 
318 gpgme_data_t
seahorse_gpgme_data_input(GInputStream * input)319 seahorse_gpgme_data_input (GInputStream* input)
320 {
321 	gpgme_error_t gerr;
322 	gpgme_data_t ret = NULL;
323 
324 	g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
325 
326 	gerr = gpgme_data_new_from_cbs (&ret, &input_cbs, input);
327 	if (!GPG_IS_OK (gerr))
328 		return NULL;
329 
330 	g_object_ref (input);
331 	return ret;
332 }
333 
334 gpgme_data_t
seahorse_gpgme_data_new()335 seahorse_gpgme_data_new ()
336 {
337 	gpgme_error_t gerr;
338 	gpgme_data_t data;
339 
340 	gerr = gpgme_data_new (&data);
341 	if (!GPG_IS_OK (gerr)) {
342 		if (gpgme_err_code_to_errno (gerr) == ENOMEM ||
343 		    gpgme_err_code (gerr) == GPG_ERR_ENOMEM) {
344 
345 			g_error ("%s: failed to allocate gpgme_data_t", G_STRLOC);
346 
347 		} else {
348 			/* The only reason this should fail is above */
349 			g_assert_not_reached ();
350 
351 			/* Just in case */
352 			abort ();
353 		}
354 	}
355 
356 	return data;
357 }
358 
359 gpgme_data_t
seahorse_gpgme_data_new_from_mem(const char * buffer,size_t size,gboolean copy)360 seahorse_gpgme_data_new_from_mem (const char *buffer, size_t size, gboolean copy)
361 {
362 	gpgme_data_t data;
363 	gpgme_error_t gerr;
364 
365 	gerr = gpgme_data_new_from_mem (&data, buffer, size, copy ? 1 : 0);
366 	if (!GPG_IS_OK (gerr)) {
367 		if (gpgme_err_code_to_errno (gerr) == ENOMEM ||
368 		    gpgme_err_code (gerr) == GPG_ERR_ENOMEM) {
369 
370 			g_error ("%s: failed to allocate gpgme_data_t", G_STRLOC);
371 
372 		} else {
373 			/* The only reason this should fail is above */
374 			g_assert_not_reached ();
375 
376 			/* Just in case */
377 			abort ();
378 		}
379 	}
380 
381 	return data;
382 }
383 
384 int
seahorse_gpgme_data_write_all(gpgme_data_t data,const void * buffer,size_t len)385 seahorse_gpgme_data_write_all (gpgme_data_t data, const void* buffer, size_t len)
386 {
387 	guchar *text = (guchar*)buffer;
388 	int written = 0;
389 
390 	if (len < 0)
391 		len = strlen ((char *) text);
392 
393 	while (len > 0) {
394 		written = gpgme_data_write (data, (void*)text, len);
395 		if (written < 0) {
396 			if (errno == EAGAIN || errno == EINTR)
397 				continue;
398 			return -1;
399 		}
400 
401 		len -= written;
402 		text += written;
403 	}
404 
405 	return written;
406 }
407 
408 void
seahorse_gpgme_data_release(gpgme_data_t data)409 seahorse_gpgme_data_release (gpgme_data_t data)
410 {
411 	if (data)
412 		gpgme_data_release (data);
413 }
414