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/>.
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))
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. */
52 init_membuf (struct membuf
*mb
, int initiallen
, size_t maxlen
)
55 mb
->size
= initiallen
;
59 /* we need to allocate one byte more for get_membuf */
60 mb
->buf
= xtrymalloc (initiallen
+1);
66 put_membuf (struct membuf
*mb
, const void *buf
, size_t len
)
68 if (mb
->out_of_core
|| mb
->too_large
)
71 if (mb
->maxlen
&& mb
->len
+ len
> mb
->maxlen
)
77 if (mb
->len
+ len
>= mb
->size
)
81 mb
->size
+= len
+ 1024;
82 /* we need to allocate one byte more for get_membuf */
83 p
= xtryrealloc (mb
->buf
, mb
->size
+1);
91 memcpy (mb
->buf
+ mb
->len
, buf
, len
);
96 get_membuf (struct membuf
*mb
, size_t *len
)
100 if (mb
->out_of_core
|| mb
->too_large
)
107 mb
->buf
[mb
->len
] = 0; /* there is enough space for the hidden eos */
111 mb
->out_of_core
= 1; /* don't allow a reuse */
116 free_membuf (struct membuf
*mb
)
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
137 assuan_inquire (assuan_context_t ctx
, const char *keyword
,
138 unsigned char **r_buffer
, size_t *r_length
, size_t maxlen
)
142 char cmdbuf
[LINELENGTH
-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
143 unsigned char *line
, *p
;
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
);
153 return _assuan_error (ASSUAN_Not_A_Server
);
155 return _assuan_error (ASSUAN_Nested_Commands
);
159 memset (&mb
, 0, sizeof mb
); /* avoid compiler warnings */
161 init_membuf (&mb
, maxlen
? maxlen
:1024, maxlen
);
163 strcpy (stpcpy (cmdbuf
, "INQUIRE "), keyword
);
164 rc
= assuan_write_line (ctx
, cmdbuf
);
173 rc
= _assuan_read_line (ctx
);
174 while (_assuan_error_is_eagain (rc
));
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
);
189 if (line
[0] != 'D' || line
[1] != ' ' || nodataexpected
)
191 rc
= _assuan_error (ASSUAN_Unexpected_Command
);
202 for (;linelen
&& *p
!= '%'; linelen
--, p
++)
204 put_membuf (&mb
, line
, p
-line
);
206 { /* handle escaping */
207 unsigned char tmp
[1];
212 put_membuf (&mb
, tmp
, 1);
218 rc
= _assuan_error (ASSUAN_Too_Much_Data
);
225 *r_buffer
= get_membuf (&mb
, r_length
);
227 rc
= _assuan_error (ASSUAN_Out_Of_Core
);
239 _assuan_inquire_release (assuan_context_t ctx
)
243 if (ctx
->inquire_membuf
)
245 free_membuf (ctx
->inquire_membuf
);
246 free (ctx
->inquire_membuf
);
254 _assuan_inquire_ext_cb (assuan_context_t ctx
)
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
);
271 if (line
[0] == 'E' && line
[1] == 'N' && line
[2] == 'D'
272 && (!line
[3] || line
[3] == ' '))
278 if (line
[0] != 'D' || line
[1] != ' ' || mb
== NULL
)
280 rc
= _assuan_error (ASSUAN_Unexpected_Command
);
292 for (;linelen
&& *p
!= '%'; linelen
--, p
++)
294 put_membuf (mb
, line
, p
-line
);
296 { /* handle escaping */
297 unsigned char tmp
[1];
302 put_membuf (mb
, tmp
, 1);
308 rc
= _assuan_error (ASSUAN_Too_Much_Data
);
317 unsigned char *buf
= NULL
;
321 buf
= get_membuf (mb
, &buf_len
);
323 rc
= _assuan_error (ASSUAN_Out_Of_Core
);
326 ctx
->inquire_membuf
= NULL
;
329 rc
= (ctx
->inquire_cb
) (ctx
->inquire_cb_data
, rc
, buf
, buf_len
);
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
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
,
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
);
361 return _assuan_error (ASSUAN_Not_A_Server
);
363 return _assuan_error (ASSUAN_Nested_Commands
);
365 mb
= malloc (sizeof (struct membuf
));
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
);
381 /* Set up the continuation. */
382 ctx
->inquire_cb
= cb
;
383 ctx
->inquire_cb_data
= cb_data
;
384 ctx
->inquire_membuf
= mb
;