Add support for gpg --fetch-keys.
[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 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29
30 #include "gpgme.h"
31 #include "data.h"
32 #include "util.h"
33 #include "ops.h"
34 #include "priv-io.h"
35 #include "debug.h"
36
37 \f
38 gpgme_error_t
39 _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
40 {
41   gpgme_data_t dh;
42
43   if (!r_dh)
44     return gpg_error (GPG_ERR_INV_VALUE);
45
46   *r_dh = NULL;
47   dh = calloc (1, sizeof (*dh));
48   if (!dh)
49     return gpg_error_from_errno (errno);
50
51   dh->cbs = cbs;
52
53   *r_dh = dh;
54   return 0;
55 }
56
57
58 void
59 _gpgme_data_release (gpgme_data_t dh)
60 {
61   if (!dh)
62     return;
63
64   if (dh->file_name)
65     free (dh->file_name);
66   free (dh);
67 }
68
69 \f
70 /* Read up to SIZE bytes into buffer BUFFER from the data object with
71    the handle DH.  Return the number of characters read, 0 on EOF and
72    -1 on error.  If an error occurs, errno is set.  */
73 ssize_t
74 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
75 {
76   ssize_t res;
77   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh,
78               "buffer=%p, size=%u", buffer, size);
79
80   if (!dh)
81     {
82       errno = EINVAL;
83       return TRACE_SYSRES (-1);
84     }
85   if (!dh->cbs->read)
86     {
87       errno = ENOSYS;
88       return TRACE_SYSRES (-1);
89     }
90   do
91     res = (*dh->cbs->read) (dh, buffer, size);
92   while (res < 0 && errno == EINTR);
93
94   return TRACE_SYSRES (res);
95 }
96
97
98 /* Write up to SIZE bytes from buffer BUFFER to the data object with
99    the handle DH.  Return the number of characters written, or -1 on
100    error.  If an error occurs, errno is set.  */
101 ssize_t
102 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
103 {
104   ssize_t res;
105   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh,
106               "buffer=%p, size=%u", buffer, size);
107
108   if (!dh)
109     {
110       errno = EINVAL;
111       return TRACE_SYSRES (-1);
112     }
113   if (!dh->cbs->write)
114     {
115       errno = ENOSYS;
116       return TRACE_SYSRES (-1);
117     }
118   do
119     res = (*dh->cbs->write) (dh, buffer, size);
120   while (res < 0 && errno == EINTR);
121
122   return TRACE_SYSRES (res);
123 }
124
125
126 /* Set the current position from where the next read or write starts
127    in the data object with the handle DH to OFFSET, relativ to
128    WHENCE.  */
129 off_t
130 gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
131 {
132   TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh,
133               "offset=%lli, whence=%i", offset, whence);
134
135   if (!dh)
136     {
137       errno = EINVAL;
138       return TRACE_SYSRES (-1);
139     }
140   if (!dh->cbs->seek)
141     {
142       errno = ENOSYS;
143       return TRACE_SYSRES (-1);
144     }
145
146   /* For relative movement, we must take into account the actual
147      position of the read counter.  */
148   if (whence == SEEK_CUR)
149     offset -= dh->pending_len;
150
151   offset = (*dh->cbs->seek) (dh, offset, whence);
152   if (offset >= 0)
153     dh->pending_len = 0;
154
155   return TRACE_SYSRES (offset);
156 }
157
158
159 /* Release the data object with the handle DH.  */
160 void
161 gpgme_data_release (gpgme_data_t dh)
162 {
163   TRACE (DEBUG_DATA, "gpgme_data_release", dh);
164
165   if (!dh)
166     return;
167
168   if (dh->cbs->release)
169     (*dh->cbs->release) (dh);
170   _gpgme_data_release (dh);
171 }
172
173
174 /* Get the current encoding meta information for the data object with
175    handle DH.  */
176 gpgme_data_encoding_t
177 gpgme_data_get_encoding (gpgme_data_t dh)
178 {
179   TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh,
180           "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE);
181   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
182 }
183
184
185 /* Set the encoding meta information for the data object with handle
186    DH to ENC.  */
187 gpgme_error_t
188 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
189 {
190   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh,
191               "encoding=%i", enc);
192   if (!dh)
193     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
194   if (enc < 0 || enc > GPGME_DATA_ENCODING_URL0)
195     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
196   dh->encoding = enc;
197   return TRACE_ERR (0);
198 }
199
200
201 /* Set the file name associated with the data object with handle DH to
202    FILE_NAME.  */
203 gpgme_error_t
204 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
205 {
206   TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh,
207               "file_name=%s", file_name);
208
209   if (!dh)
210     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
211
212   if (dh->file_name)
213     free (dh->file_name);
214
215   if (file_name)
216     {
217       dh->file_name = strdup (file_name);
218       if (!dh->file_name)
219         return TRACE_ERR (gpg_error_from_errno (errno));
220     }
221   else
222     dh->file_name = 0;
223
224   return TRACE_ERR (0);
225 }
226
227
228 /* Get the file name associated with the data object with handle DH,
229    or NULL if there is none.  */
230 char *
231 gpgme_data_get_file_name (gpgme_data_t dh)
232 {
233   if (!dh)
234     {
235       TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh);
236       return NULL;
237     }
238
239   TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh,
240           "dh->file_name=%s", dh->file_name);
241   return dh->file_name;
242 }
243
244 \f
245 /* Functions to support the wait interface.  */
246
247 gpgme_error_t
248 _gpgme_data_inbound_handler (void *opaque, int fd)
249 {
250   gpgme_data_t dh = (gpgme_data_t) opaque;
251   char buffer[BUFFER_SIZE];
252   char *bufp = buffer;
253   ssize_t buflen;
254   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh,
255               "fd=0x%x", fd);
256
257   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
258   if (buflen < 0)
259     return gpg_error_from_errno (errno);
260   if (buflen == 0)
261     {
262       _gpgme_io_close (fd);
263       return TRACE_ERR (0);
264     }
265
266   do
267     {
268       ssize_t amt = gpgme_data_write (dh, bufp, buflen);
269       if (amt == 0 || (amt < 0 && errno != EINTR))
270         return TRACE_ERR (gpg_error_from_errno (errno));
271       bufp += amt;
272       buflen -= amt;
273     }
274   while (buflen > 0);
275   return TRACE_ERR (0);
276 }
277
278
279 gpgme_error_t
280 _gpgme_data_outbound_handler (void *opaque, int fd)
281 {
282   gpgme_data_t dh = (gpgme_data_t) opaque;
283   ssize_t nwritten;
284   TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,
285               "fd=0x%x", fd);
286
287   if (!dh->pending_len)
288     {
289       ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
290       if (amt < 0)
291         return TRACE_ERR (gpg_error_from_errno (errno));
292       if (amt == 0)
293         {
294           _gpgme_io_close (fd);
295           return TRACE_ERR (0);
296         }
297       dh->pending_len = amt;
298     }
299
300   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
301   if (nwritten == -1 && errno == EAGAIN)
302     return TRACE_ERR (0);
303
304   if (nwritten == -1 && errno == EPIPE)
305     {
306       /* Not much we can do.  The other end closed the pipe, but we
307          still have data.  This should only ever happen if the other
308          end is going to tell us what happened on some other channel.
309          Silently close our end.  */
310       _gpgme_io_close (fd);
311       return TRACE_ERR (0);
312     }
313
314   if (nwritten <= 0)
315     return TRACE_ERR (gpg_error_from_errno (errno));
316
317   if (nwritten < dh->pending_len)
318     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
319   dh->pending_len -= nwritten;
320   return TRACE_ERR (0);
321 }
322
323
324 /* Get the file descriptor associated with DH, if possible.  Otherwise
325    return -1.  */
326 int
327 _gpgme_data_get_fd (gpgme_data_t dh)
328 {
329   if (!dh || !dh->cbs->get_fd)
330     return -1;
331   return (*dh->cbs->get_fd) (dh);
332 }