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