2004-09-30 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / data.c
1 /* data.c - An abstraction for data objects.
2    Copyright (C) 2002, 2003 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 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    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    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GPGME; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28
29 #include "gpgme.h"
30 #include "data.h"
31 #include "util.h"
32 #include "ops.h"
33 #include "io.h"
34
35 \f
36 gpgme_error_t
37 _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
38 {
39   gpgme_data_t dh;
40
41   if (!r_dh)
42     return gpg_error (GPG_ERR_INV_VALUE);
43
44   *r_dh = NULL;
45   dh = calloc (1, sizeof (*dh));
46   if (!dh)
47     return gpg_error_from_errno (errno);
48
49   dh->cbs = cbs;
50
51   *r_dh = dh;
52   return 0;
53 }
54
55
56 void
57 _gpgme_data_release (gpgme_data_t dh)
58 {
59   if (dh)
60     free (dh);
61 }
62
63 \f
64 /* Read up to SIZE bytes into buffer BUFFER from the data object with
65    the handle DH.  Return the number of characters read, 0 on EOF and
66    -1 on error.  If an error occurs, errno is set.  */
67 ssize_t
68 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
69 {
70   if (!dh)
71     {
72       errno = EINVAL;
73       return -1;
74     }
75   if (!dh->cbs->read)
76     {
77       errno = EOPNOTSUPP;
78       return -1;
79     }
80   return (*dh->cbs->read) (dh, buffer, size);
81 }
82
83
84 /* Write up to SIZE bytes from buffer BUFFER to the data object with
85    the handle DH.  Return the number of characters written, or -1 on
86    error.  If an error occurs, errno is set.  */
87 ssize_t
88 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
89 {
90   if (!dh)
91     {
92       errno = EINVAL;
93       return -1;
94     }
95   if (!dh->cbs->write)
96     {
97       errno = EOPNOTSUPP;
98       return -1;
99     }
100   return (*dh->cbs->write) (dh, buffer, size);
101 }
102
103
104 /* Set the current position from where the next read or write starts
105    in the data object with the handle DH to OFFSET, relativ to
106    WHENCE.  */
107 off_t
108 gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
109 {
110   if (!dh)
111     {
112       errno = EINVAL;
113       return -1;
114     }
115   if (!dh->cbs->seek)
116     {
117       errno = EOPNOTSUPP;
118       return -1;
119     }
120
121   /* For relative movement, we must take into account the actual
122      position of the read counter.  */
123   if (whence == SEEK_CUR)
124     offset -= dh->pending_len;
125
126   offset = (*dh->cbs->seek) (dh, offset, whence);
127   if (offset >= 0)
128     dh->pending_len = 0;
129
130   return offset;
131 }
132
133
134 /* Release the data object with the handle DH.  */
135 void
136 gpgme_data_release (gpgme_data_t dh)
137 {
138   if (!dh)
139     return;
140
141   if (dh->cbs->release)
142     (*dh->cbs->release) (dh);
143   _gpgme_data_release (dh);
144 }
145
146
147 /* Get the current encoding meta information for the data object with
148    handle DH.  */
149 gpgme_data_encoding_t
150 gpgme_data_get_encoding (gpgme_data_t dh)
151 {
152   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
153 }
154
155
156 /* Set the encoding meta information for the data object with handle
157    DH to ENC.  */
158 gpgme_error_t
159 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
160 {
161   if (!dh)
162     return gpg_error (GPG_ERR_INV_VALUE);
163   if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
164     return gpg_error (GPG_ERR_INV_VALUE);
165   dh->encoding = enc;
166   return 0;
167 }
168
169 \f
170 /* Functions to support the wait interface.  */
171
172 gpgme_error_t
173 _gpgme_data_inbound_handler (void *opaque, int fd)
174 {
175   gpgme_data_t dh = (gpgme_data_t) opaque;
176   char buffer[BUFFER_SIZE];
177   char *bufp = buffer;
178   ssize_t buflen;
179
180   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
181   if (buflen < 0)
182     return gpg_error_from_errno (errno);
183   if (buflen == 0)
184     {
185       _gpgme_io_close (fd);
186       return 0;
187     }
188
189   do
190     {
191       ssize_t amt = gpgme_data_write (dh, bufp, buflen);
192       if (amt == 0 || (amt < 0 && errno != EINTR))
193         return gpg_error_from_errno (errno);
194       bufp += amt;
195       buflen -= amt;
196     }
197   while (buflen > 0);
198   return 0;
199 }
200
201
202 gpgme_error_t
203 _gpgme_data_outbound_handler (void *opaque, int fd)
204 {
205   gpgme_data_t dh = (gpgme_data_t) opaque;
206   ssize_t nwritten;
207
208   if (!dh->pending_len)
209     {
210       ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
211       if (amt < 0)
212         return gpg_error_from_errno (errno);
213       if (amt == 0)
214         {
215           _gpgme_io_close (fd);
216           return 0;
217         }
218       dh->pending_len = amt;
219     }
220
221   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
222   if (nwritten == -1 && errno == EAGAIN)
223     return 0;
224
225   if (nwritten == -1 && errno == EPIPE)
226     {
227       /* Not much we can do.  The other end closed the pipe, but we
228          still have data.  This should only ever happen if the other
229          end is going to tell us what happened on some other channel.
230          Silently close our end.  */
231       _gpgme_io_close (fd);
232       return 0;
233     }
234
235   if (nwritten <= 0)
236     return gpg_error_from_errno (errno);
237
238   if (nwritten < dh->pending_len)
239     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
240   dh->pending_len -= nwritten;
241   return 0;
242 }