json: Deduplicate input handling code
[gpgme.git] / src / data.c
1 /* data.c - An abstraction for data objects.
2    Copyright (C) 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
3
4    This file is part of GPGME.
5
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <errno.h>
30 #include <string.h>
31
32 #include "gpgme.h"
33 #include "data.h"
34 #include "util.h"
35 #include "ops.h"
36 #include "priv-io.h"
37 #include "debug.h"
38
39 \f
40 gpgme_error_t
41 _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
42 {
43   gpgme_data_t dh;
44
45   if (!r_dh)
46     return gpg_error (GPG_ERR_INV_VALUE);
47
48   *r_dh = NULL;
49
50   if (_gpgme_selftest)
51     return _gpgme_selftest;
52
53   dh = calloc (1, sizeof (*dh));
54   if (!dh)
55     return gpg_error_from_syserror ();
56
57   dh->cbs = cbs;
58
59   *r_dh = dh;
60   return 0;
61 }
62
63
64 void
65 _gpgme_data_release (gpgme_data_t dh)
66 {
67   if (!dh)
68     return;
69
70   if (dh->file_name)
71     free (dh->file_name);
72   free (dh);
73 }
74
75 \f
76 /* Read up to SIZE bytes into buffer BUFFER from the data object with
77    the handle DH.  Return the number of characters read, 0 on EOF and
78    -1 on error.  If an error occurs, errno is set.  */
79 gpgme_ssize_t
80 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
81 {
82   gpgme_ssize_t res;
83   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
84               "buffer=%p, size=%u", buffer, size);
85
86   if (!dh)
87     {
88       gpg_err_set_errno (EINVAL);
89       return TRACE_SYSRES (-1);
90     }
91   if (!dh->cbs->read)
92     {
93       gpg_err_set_errno (ENOSYS);
94       return TRACE_SYSRES (-1);
95     }
96   do
97     res = (*dh->cbs->read) (dh, buffer, size);
98   while (res < 0 && errno == EINTR);
99
100   return TRACE_SYSRES (res);
101 }
102
103
104 /* Write up to SIZE bytes from buffer BUFFER to the data object with
105    the handle DH.  Return the number of characters written, or -1 on
106    error.  If an error occurs, errno is set.  */
107 gpgme_ssize_t
108 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
109 {
110   gpgme_ssize_t res;
111   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
112               "buffer=%p, size=%u", buffer, size);
113
114   if (!dh)
115     {
116       gpg_err_set_errno (EINVAL);
117       return TRACE_SYSRES (-1);
118     }
119   if (!dh->cbs->write)
120     {
121       gpg_err_set_errno (ENOSYS);
122       return TRACE_SYSRES (-1);
123     }
124   do
125     res = (*dh->cbs->write) (dh, buffer, size);
126   while (res < 0 && errno == EINTR);
127
128   return TRACE_SYSRES (res);
129 }
130
131
132 /* Set the current position from where the next read or write starts
133    in the data object with the handle DH to OFFSET, relativ to
134    WHENCE.  */
135 gpgme_off_t
136 gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence)
137 {
138   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
139               "offset=%lli, whence=%i", offset, whence);
140
141   if (!dh)
142     {
143       gpg_err_set_errno (EINVAL);
144       return TRACE_SYSRES (-1);
145     }
146   if (!dh->cbs->seek)
147     {
148       gpg_err_set_errno (ENOSYS);
149       return TRACE_SYSRES (-1);
150     }
151
152   /* For relative movement, we must take into account the actual
153      position of the read counter.  */
154   if (whence == SEEK_CUR)
155     offset -= dh->pending_len;
156
157   offset = (*dh->cbs->seek) (dh, offset, whence);
158   if (offset >= 0)
159     dh->pending_len = 0;
160
161   return TRACE_SYSRES (offset);
162 }
163
164
165 /* Convenience function to do a gpgme_data_seek (dh, 0, SEEK_SET).  */
166 gpgme_error_t
167 gpgme_data_rewind (gpgme_data_t dh)
168 {
169   gpgme_error_t err;
170   TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh);
171
172   err = ((gpgme_data_seek (dh, 0, SEEK_SET) == -1)
173          ? gpg_error_from_syserror () : 0);
174
175   return TRACE_ERR (err);
176 }
177
178
179 /* Release the data object with the handle DH.  */
180 void
181 gpgme_data_release (gpgme_data_t dh)
182 {
183   TRACE (DEBUG_DATA, "gpgme_data_release", dh);
184
185   if (!dh)
186     return;
187
188   if (dh->cbs->release)
189     (*dh->cbs->release) (dh);
190   _gpgme_data_release (dh);
191 }
192
193
194 /* Get the current encoding meta information for the data object with
195    handle DH.  */
196 gpgme_data_encoding_t
197 gpgme_data_get_encoding (gpgme_data_t dh)
198 {
199   TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
200           "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
201   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
202 }
203
204
205 /* Set the encoding meta information for the data object with handle
206    DH to ENC.  */
207 gpgme_error_t
208 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
209 {
210   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
211               "encoding=%i", enc);
212   if (!dh)
213     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
214   if (enc < 0 || enc > GPGME_DATA_ENCODING_MIME)
215     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
216   dh->encoding = enc;
217   return TRACE_ERR (0);
218 }
219
220
221 /* Set the file name associated with the data object with handle DH to
222    FILE_NAME.  */
223 gpgme_error_t
224 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
225 {
226   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
227               "file_name=%s", file_name);
228
229   if (!dh)
230     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
231
232   if (dh->file_name)
233     free (dh->file_name);
234
235   if (file_name)
236     {
237       dh->file_name = strdup (file_name);
238       if (!dh->file_name)
239         return TRACE_ERR (gpg_error_from_syserror ());
240     }
241   else
242     dh->file_name = 0;
243
244   return TRACE_ERR (0);
245 }
246
247
248 /* Get the file name associated with the data object with handle DH,
249    or NULL if there is none.  */
250 char *
251 gpgme_data_get_file_name (gpgme_data_t dh)
252 {
253   if (!dh)
254     {
255       TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
256       return NULL;
257     }
258
259   TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
260           "dh->file_name=%s", dh->file_name);
261   return dh->file_name;
262 }
263
264
265 /* Set a flag for the data object DH.  See the manual for details.  */
266 gpg_error_t
267 gpgme_data_set_flag (gpgme_data_t dh, const char *name, const char *value)
268 {
269   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_set_flag", dh,
270               "%s=%s", name, value);
271
272   if (!dh)
273     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
274
275   if (!strcmp (name, "size-hint"))
276     {
277       dh->size_hint= value? _gpgme_string_to_off (value) : 0;
278     }
279   else
280     return gpg_error (GPG_ERR_UNKNOWN_NAME);
281
282   return 0;
283 }
284
285
286 \f
287 /* Functions to support the wait interface.  */
288
289 gpgme_error_t
290 _gpgme_data_inbound_handler (void *opaque, int fd)
291 {
292   struct io_cb_data *data = (struct io_cb_data *) opaque;
293   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
294   char buffer[BUFFER_SIZE];
295   char *bufp = buffer;
296   gpgme_ssize_t buflen;
297   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
298               "fd=0x%x", fd);
299
300   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
301   if (buflen < 0)
302     return gpg_error_from_syserror ();
303   if (buflen == 0)
304     {
305       _gpgme_io_close (fd);
306       return TRACE_ERR (0);
307     }
308
309   do
310     {
311       gpgme_ssize_t amt = gpgme_data_write (dh, bufp, buflen);
312       if (amt == 0 || (amt < 0 && errno != EINTR))
313         return TRACE_ERR (gpg_error_from_syserror ());
314       bufp += amt;
315       buflen -= amt;
316     }
317   while (buflen > 0);
318   return TRACE_ERR (0);
319 }
320
321
322 gpgme_error_t
323 _gpgme_data_outbound_handler (void *opaque, int fd)
324 {
325   struct io_cb_data *data = (struct io_cb_data *) opaque;
326   gpgme_data_t dh = (gpgme_data_t) data->handler_value;
327   gpgme_ssize_t nwritten;
328   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
329               "fd=0x%x", fd);
330
331   if (!dh->pending_len)
332     {
333       gpgme_ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
334       if (amt < 0)
335         return TRACE_ERR (gpg_error_from_syserror ());
336       if (amt == 0)
337         {
338           _gpgme_io_close (fd);
339           return TRACE_ERR (0);
340         }
341       dh->pending_len = amt;
342     }
343
344   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
345   if (nwritten == -1 && errno == EAGAIN)
346     return TRACE_ERR (0);
347
348   if (nwritten == -1 && errno == EPIPE)
349     {
350       /* Not much we can do.  The other end closed the pipe, but we
351          still have data.  This should only ever happen if the other
352          end is going to tell us what happened on some other channel.
353          Silently close our end.  */
354       _gpgme_io_close (fd);
355       return TRACE_ERR (0);
356     }
357
358   if (nwritten <= 0)
359     return TRACE_ERR (gpg_error_from_syserror ());
360
361   if (nwritten < dh->pending_len)
362     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
363   dh->pending_len -= nwritten;
364   return TRACE_ERR (0);
365 }
366
367
368 /* Get the file descriptor associated with DH, if possible.  Otherwise
369    return -1.  */
370 int
371 _gpgme_data_get_fd (gpgme_data_t dh)
372 {
373   if (!dh || !dh->cbs->get_fd)
374     return -1;
375   return (*dh->cbs->get_fd) (dh);
376 }
377
378
379 /* Get the size-hint value for DH or 0 if not available.  */
380 gpgme_off_t
381 _gpgme_data_get_size_hint (gpgme_data_t dh)
382 {
383   return dh ? dh->size_hint : 0;
384 }