Call libssh2_channel_close() before freeing it.
[libpwmd.git] / assuan / assuan-inquire.c
blob58b9f0297682c36d5dec1920d24bd75eace55e40
1 /* assuan-inquire.c - handle inquire stuff
2 * Copyright (C) 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
4 * This file is part of Assuan.
6 * Assuan 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.
11 * Assuan 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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
25 #include "assuan-defs.h"
27 #define digitp(a) ((a) >= '0' && (a) <= '9')
28 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
29 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
30 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
33 struct membuf
35 size_t len;
36 size_t size;
37 char *buf;
38 int out_of_core;
39 int too_large;
40 size_t maxlen;
45 /* A simple implementation of a dynamic buffer. Use init_membuf() to
46 create a buffer, put_membuf to append bytes and get_membuf to
47 release and return the buffer. Allocation errors are detected but
48 only returned at the final get_membuf(), this helps not to clutter
49 the code with out of core checks. */
51 static void
52 init_membuf (struct membuf *mb, int initiallen, size_t maxlen)
54 mb->len = 0;
55 mb->size = initiallen;
56 mb->out_of_core = 0;
57 mb->too_large = 0;
58 mb->maxlen = maxlen;
59 /* we need to allocate one byte more for get_membuf */
60 mb->buf = xtrymalloc (initiallen+1);
61 if (!mb->buf)
62 mb->out_of_core = 1;
65 static void
66 put_membuf (struct membuf *mb, const void *buf, size_t len)
68 if (mb->out_of_core || mb->too_large)
69 return;
71 if (mb->maxlen && mb->len + len > mb->maxlen)
73 mb->too_large = 1;
74 return;
77 if (mb->len + len >= mb->size)
79 char *p;
81 mb->size += len + 1024;
82 /* we need to allocate one byte more for get_membuf */
83 p = xtryrealloc (mb->buf, mb->size+1);
84 if (!p)
86 mb->out_of_core = 1;
87 return;
89 mb->buf = p;
91 memcpy (mb->buf + mb->len, buf, len);
92 mb->len += len;
95 static void *
96 get_membuf (struct membuf *mb, size_t *len)
98 char *p;
100 if (mb->out_of_core || mb->too_large)
102 xfree (mb->buf);
103 mb->buf = NULL;
104 return NULL;
107 mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
108 p = mb->buf;
109 *len = mb->len;
110 mb->buf = NULL;
111 mb->out_of_core = 1; /* don't allow a reuse */
112 return p;
115 static void
116 free_membuf (struct membuf *mb)
118 xfree (mb->buf);
119 mb->buf = NULL;
124 * assuan_inquire:
125 * @ctx: An assuan context
126 * @keyword: The keyword used for the inquire
127 * @r_buffer: Returns an allocated buffer
128 * @r_length: Returns the length of this buffer
129 * @maxlen: If not 0, the size limit of the inquired data.
131 * A Server may use this to Send an inquire. r_buffer, r_length and
132 * maxlen may all be NULL/0 to indicate that no real data is expected.
134 * Return value: 0 on success or an ASSUAN error code
136 assuan_error_t
137 assuan_inquire (assuan_context_t ctx, const char *keyword,
138 unsigned char **r_buffer, size_t *r_length, size_t maxlen)
140 assuan_error_t rc;
141 struct membuf mb;
142 char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
143 unsigned char *line, *p;
144 int linelen;
145 int nodataexpected;
147 if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
148 return _assuan_error (ASSUAN_Invalid_Value);
149 nodataexpected = !r_buffer && !r_length && !maxlen;
150 if (!nodataexpected && (!r_buffer || !r_length))
151 return _assuan_error (ASSUAN_Invalid_Value);
152 if (!ctx->is_server)
153 return _assuan_error (ASSUAN_Not_A_Server);
154 if (ctx->in_inquire)
155 return _assuan_error (ASSUAN_Nested_Commands);
157 ctx->in_inquire = 1;
158 if (nodataexpected)
159 memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
160 else
161 init_membuf (&mb, maxlen? maxlen:1024, maxlen);
163 strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
164 rc = assuan_write_line (ctx, cmdbuf);
165 if (rc)
166 goto leave;
168 for (;;)
173 rc = _assuan_read_line (ctx);
174 while (_assuan_error_is_eagain (rc));
175 if (rc)
176 goto leave;
177 line = (unsigned char *) ctx->inbound.line;
178 linelen = ctx->inbound.linelen;
180 while (*line == '#' || !linelen);
181 if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
182 && (!line[3] || line[3] == ' '))
183 break; /* END command received*/
184 if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
186 rc = _assuan_error (ASSUAN_Canceled);
187 goto leave;
189 if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
191 rc = _assuan_error (ASSUAN_Unexpected_Command);
192 goto leave;
194 if (linelen < 3)
195 continue;
196 line += 2;
197 linelen -= 2;
199 p = line;
200 while (linelen)
202 for (;linelen && *p != '%'; linelen--, p++)
204 put_membuf (&mb, line, p-line);
205 if (linelen > 2)
206 { /* handle escaping */
207 unsigned char tmp[1];
208 p++;
209 *tmp = xtoi_2 (p);
210 p += 2;
211 linelen -= 3;
212 put_membuf (&mb, tmp, 1);
214 line = p;
216 if (mb.too_large)
218 rc = _assuan_error (ASSUAN_Too_Much_Data);
219 goto leave;
223 if (!nodataexpected)
225 *r_buffer = get_membuf (&mb, r_length);
226 if (!*r_buffer)
227 rc = _assuan_error (ASSUAN_Out_Of_Core);
230 leave:
231 if (!nodataexpected)
232 free_membuf (&mb);
233 ctx->in_inquire = 0;
234 return rc;
238 void
239 _assuan_inquire_release (assuan_context_t ctx)
241 if (ctx->in_inquire)
243 if (ctx->inquire_membuf)
245 free_membuf (ctx->inquire_membuf);
246 free (ctx->inquire_membuf);
248 ctx->in_inquire = 0;
254 _assuan_inquire_ext_cb (assuan_context_t ctx)
256 int rc;
257 unsigned char *line;
258 int linelen;
259 struct membuf *mb;
260 unsigned char *p;
262 line = (unsigned char *) ctx->inbound.line;
263 linelen = ctx->inbound.linelen;
264 mb = ctx->inquire_membuf;
266 if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
268 rc = _assuan_error (ASSUAN_Canceled);
269 goto leave;
271 if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
272 && (!line[3] || line[3] == ' '))
274 rc = 0;
275 goto leave;
278 if (line[0] != 'D' || line[1] != ' ' || mb == NULL)
280 rc = _assuan_error (ASSUAN_Unexpected_Command);
281 goto leave;
284 if (linelen < 3)
285 return 0;
286 line += 2;
287 linelen -= 2;
289 p = line;
290 while (linelen)
292 for (;linelen && *p != '%'; linelen--, p++)
294 put_membuf (mb, line, p-line);
295 if (linelen > 2)
296 { /* handle escaping */
297 unsigned char tmp[1];
298 p++;
299 *tmp = xtoi_2 (p);
300 p += 2;
301 linelen -= 3;
302 put_membuf (mb, tmp, 1);
304 line = p;
306 if (mb->too_large)
308 rc = _assuan_error (ASSUAN_Too_Much_Data);
309 goto leave;
312 return 0;
314 leave:
316 size_t buf_len = 0;
317 unsigned char *buf = NULL;
319 if (mb)
321 buf = get_membuf (mb, &buf_len);
322 if (!buf)
323 rc = _assuan_error (ASSUAN_Out_Of_Core);
324 free_membuf (mb);
325 free (mb);
326 ctx->inquire_membuf = NULL;
328 ctx->in_inquire = 0;
329 rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len);
331 return rc;
335 * assuan_inquire_ext:
336 * @ctx: An assuan context
337 * @keyword: The keyword used for the inquire
338 * @maxlen: If not 0, the size limit of the inquired data.
339 * @cb: A callback handler which is invoked after the operation completed.
340 * @cb_data: A user-provided value passed to the callback handler.
342 * A Server may use this to Send an inquire. r_buffer, r_length and
343 * maxlen may all be NULL/0 to indicate that no real data is expected.
344 * When this function returns,
346 * Return value: 0 on success or an ASSUAN error code
348 assuan_error_t
349 assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen,
350 int (*cb) (void *cb_data, int rc, unsigned char *buf,
351 size_t len),
352 void *cb_data)
354 assuan_error_t rc;
355 struct membuf *mb = NULL;
356 char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
358 if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
359 return _assuan_error (ASSUAN_Invalid_Value);
360 if (!ctx->is_server)
361 return _assuan_error (ASSUAN_Not_A_Server);
362 if (ctx->in_inquire)
363 return _assuan_error (ASSUAN_Nested_Commands);
365 mb = malloc (sizeof (struct membuf));
366 if (!mb)
367 return _assuan_error (ASSUAN_Out_Of_Core);
368 init_membuf (mb, maxlen ? maxlen : 1024, maxlen);
370 strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
371 rc = assuan_write_line (ctx, cmdbuf);
372 if (rc)
374 free_membuf (mb);
375 free (mb);
376 return rc;
379 ctx->in_inquire = 1;
381 /* Set up the continuation. */
382 ctx->inquire_cb = cb;
383 ctx->inquire_cb_data = cb_data;
384 ctx->inquire_membuf = mb;
386 return 0;