Unset the DISPLAY and TERM environment variables just before forking. A
[pwmd.git] / assuan / src / assuan-handler.c
blob55b83c32e4ec73282e52fce7db9d12c3f3a1c0de
1 /* assuan-handler.c - dispatch commands
2 * Copyright (C) 2001, 2002, 2003, 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>
24 #include <errno.h>
26 #include "assuan-defs.h"
30 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
31 #define digitp(a) ((a) >= '0' && (a) <= '9')
33 static int my_strcasecmp (const char *a, const char *b);
36 #define PROCESS_DONE(ctx, rc) \
37 ((ctx)->in_process_next ? assuan_process_done ((ctx), (rc)) : (rc))
39 static int
40 dummy_handler (assuan_context_t ctx, char *line)
42 return
43 PROCESS_DONE (ctx, set_error (ctx, Server_Fault, "no handler registered"));
47 static int
48 std_handler_nop (assuan_context_t ctx, char *line)
50 return PROCESS_DONE (ctx, 0); /* okay */
53 static int
54 std_handler_cancel (assuan_context_t ctx, char *line)
56 if (ctx->cancel_notify_fnc)
57 ctx->cancel_notify_fnc (ctx);
58 return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
61 static int
62 std_handler_option (assuan_context_t ctx, char *line)
64 char *key, *value, *p;
66 for (key=line; spacep (key); key++)
68 if (!*key)
69 return
70 PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, "argument required"));
71 if (*key == '=')
72 return
73 PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
74 "no option name given"));
75 for (value=key; *value && !spacep (value) && *value != '='; value++)
77 if (*value)
79 if (spacep (value))
80 *value++ = 0; /* terminate key */
81 for (; spacep (value); value++)
83 if (*value == '=')
85 *value++ = 0; /* terminate key */
86 for (; spacep (value); value++)
88 if (!*value)
89 return
90 PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
91 "option argument expected"));
93 if (*value)
95 for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
97 if (p > value)
98 *++p = 0; /* strip trailing spaces */
102 if (*key == '-' && key[1] == '-' && key[2])
103 key += 2; /* the double dashes are optional */
104 if (*key == '-')
105 return PROCESS_DONE (ctx,
106 set_error (ctx, Syntax_Error,
107 "option should not begin with one dash"));
109 if (ctx->option_handler_fnc)
110 return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
111 return PROCESS_DONE (ctx, 0);
114 static int
115 std_handler_bye (assuan_context_t ctx, char *line)
117 if (ctx->bye_notify_fnc)
118 ctx->bye_notify_fnc (ctx);
119 assuan_close_input_fd (ctx);
120 assuan_close_output_fd (ctx);
121 return PROCESS_DONE (ctx, _assuan_error (-1)); /* pretty simple :-) */
124 static int
125 std_handler_auth (assuan_context_t ctx, char *line)
127 return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
130 static int
131 std_handler_reset (assuan_context_t ctx, char *line)
133 if (ctx->reset_notify_fnc)
134 ctx->reset_notify_fnc (ctx);
135 assuan_close_input_fd (ctx);
136 assuan_close_output_fd (ctx);
137 _assuan_uds_close_fds (ctx);
138 return PROCESS_DONE (ctx, 0);
141 static int
142 std_handler_help (assuan_context_t ctx, char *line)
144 unsigned int i;
145 char buf[ASSUAN_LINELENGTH];
147 for (i = 0; i < ctx->cmdtbl_used; i++)
149 snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name);
150 buf[ASSUAN_LINELENGTH - 1] = '\0';
151 assuan_write_line (ctx, buf);
154 return PROCESS_DONE (ctx, 0);
158 static int
159 std_handler_end (assuan_context_t ctx, char *line)
161 return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
165 assuan_error_t
166 assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd)
168 char *endp;
170 if ((strncmp (line, "FD", 2) && strncmp (line, "fd", 2))
171 || (line[2] != '=' && line[2] != '\0' && !spacep(&line[2])))
172 return set_error (ctx, Syntax_Error, "FD[=<n>] expected");
173 line += 2;
174 if (*line == '=')
176 line ++;
177 if (!digitp (*line))
178 return set_error (ctx, Syntax_Error, "number required");
179 #ifdef HAVE_W32_SYSTEM
180 /* Fixme: For a W32/64bit system we will need to change the cast
181 and the conversion fucntion. */
182 *rfd = (void*)strtoul (line, &endp, 10);
183 #else
184 *rfd = strtoul (line, &endp, 10);
185 #endif
186 /* Remove that argument so that a notify handler won't see it. */
187 memset (line, ' ', endp? (endp-line):strlen(line));
189 if (*rfd == ctx->inbound.fd)
190 return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
191 if (*rfd == ctx->outbound.fd)
192 return set_error (ctx, Parameter_Conflict, "fd same as outbound fd");
193 return 0;
195 else
196 /* Our peer has sent the file descriptor. */
197 return assuan_receivefd (ctx, rfd);
201 /* Format is INPUT FD=<n> */
202 static int
203 std_handler_input (assuan_context_t ctx, char *line)
205 int rc;
206 assuan_fd_t fd;
208 rc = assuan_command_parse_fd (ctx, line, &fd);
209 if (rc)
210 return PROCESS_DONE (ctx, rc);
211 ctx->input_fd = fd;
212 if (ctx->input_notify_fnc)
213 ctx->input_notify_fnc (ctx, line);
214 return PROCESS_DONE (ctx, 0);
217 /* Format is OUTPUT FD=<n> */
218 static int
219 std_handler_output (assuan_context_t ctx, char *line)
221 int rc;
222 assuan_fd_t fd;
224 rc = assuan_command_parse_fd (ctx, line, &fd);
225 if (rc)
226 return PROCESS_DONE (ctx, rc);
227 ctx->output_fd = fd;
228 if (ctx->output_notify_fnc)
229 ctx->output_notify_fnc (ctx, line);
230 return PROCESS_DONE (ctx, 0);
237 /* This is a table with the standard commands and handler for them.
238 The table is used to initialize a new context and associate strings
239 with default handlers */
240 static struct {
241 const char *name;
242 int (*handler)(assuan_context_t, char *line);
243 int always; /* always initialize this command */
244 } std_cmd_table[] = {
245 { "NOP", std_handler_nop, 1 },
246 { "CANCEL", std_handler_cancel, 1 },
247 { "OPTION", std_handler_option, 1 },
248 { "BYE", std_handler_bye, 1 },
249 { "AUTH", std_handler_auth, 1 },
250 { "RESET", std_handler_reset, 1 },
251 { "END", std_handler_end, 1 },
252 { "HELP", std_handler_help, 1 },
254 { "INPUT", std_handler_input, 0 },
255 { "OUTPUT", std_handler_output, 0 },
256 { NULL, NULL, 0 }
261 * assuan_register_command:
262 * @ctx: the server context
263 * @cmd_name: A string with the command name
264 * @handler: The handler function to be called or NULL to use a default
265 * handler.
267 * Register a handler to be used for a given command. Note that
268 * several default handlers are already regsitered with a new context.
269 * This function however allows to override them.
271 * Return value: 0 on success or an error code
274 assuan_register_command (assuan_context_t ctx,
275 const char *cmd_name,
276 int (*handler)(assuan_context_t, char *))
278 int i;
279 const char *s;
281 if (cmd_name && !*cmd_name)
282 cmd_name = NULL;
284 if (!cmd_name)
285 return _assuan_error (ASSUAN_Invalid_Value);
287 if (!handler)
288 { /* find a default handler. */
289 for (i=0; (s=std_cmd_table[i].name) && strcmp (cmd_name, s); i++)
291 if (!s)
292 { /* Try again but case insensitive. */
293 for (i=0; (s=std_cmd_table[i].name)
294 && my_strcasecmp (cmd_name, s); i++)
297 if (s)
298 handler = std_cmd_table[i].handler;
299 if (!handler)
300 handler = dummy_handler; /* Last resort is the dummy handler. */
303 if (!ctx->cmdtbl)
305 ctx->cmdtbl_size = 50;
306 ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
307 if (!ctx->cmdtbl)
308 return _assuan_error (ASSUAN_Out_Of_Core);
309 ctx->cmdtbl_used = 0;
311 else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
313 struct cmdtbl_s *x;
315 x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
316 if (!x)
317 return _assuan_error (ASSUAN_Out_Of_Core);
318 ctx->cmdtbl = x;
319 ctx->cmdtbl_size += 50;
322 ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
323 ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
324 ctx->cmdtbl_used++;
325 return 0;
329 assuan_register_post_cmd_notify (assuan_context_t ctx,
330 void (*fnc)(assuan_context_t, int))
332 if (!ctx)
333 return _assuan_error (ASSUAN_Invalid_Value);
334 ctx->post_cmd_notify_fnc = fnc;
335 return 0;
339 assuan_register_pre_cmd_notify (assuan_context_t ctx,
340 int (*fnc)(assuan_context_t, const char *))
342 if (!ctx)
343 return _assuan_error (ASSUAN_Invalid_Value);
344 ctx->pre_cmd_notify_fnc = fnc;
345 return 0;
349 assuan_register_bye_notify (assuan_context_t ctx,
350 void (*fnc)(assuan_context_t))
352 if (!ctx)
353 return _assuan_error (ASSUAN_Invalid_Value);
354 ctx->bye_notify_fnc = fnc;
355 return 0;
359 assuan_register_reset_notify (assuan_context_t ctx,
360 void (*fnc)(assuan_context_t))
362 if (!ctx)
363 return _assuan_error (ASSUAN_Invalid_Value);
364 ctx->reset_notify_fnc = fnc;
365 return 0;
369 assuan_register_cancel_notify (assuan_context_t ctx,
370 void (*fnc)(assuan_context_t))
372 if (!ctx)
373 return _assuan_error (ASSUAN_Invalid_Value);
374 ctx->cancel_notify_fnc = fnc;
375 return 0;
379 assuan_register_option_handler (assuan_context_t ctx,
380 int (*fnc)(assuan_context_t,
381 const char*, const char*))
383 if (!ctx)
384 return _assuan_error (ASSUAN_Invalid_Value);
385 ctx->option_handler_fnc = fnc;
386 return 0;
390 assuan_register_input_notify (assuan_context_t ctx,
391 void (*fnc)(assuan_context_t, const char *))
393 if (!ctx)
394 return _assuan_error (ASSUAN_Invalid_Value);
395 ctx->input_notify_fnc = fnc;
396 return 0;
400 assuan_register_output_notify (assuan_context_t ctx,
401 void (*fnc)(assuan_context_t, const char *))
403 if (!ctx)
404 return _assuan_error (ASSUAN_Invalid_Value);
405 ctx->output_notify_fnc = fnc;
406 return 0;
410 /* Helper to register the standards commands */
412 _assuan_register_std_commands (assuan_context_t ctx)
414 int i, rc;
416 for (i=0; std_cmd_table[i].name; i++)
418 if (std_cmd_table[i].always)
420 rc = assuan_register_command (ctx, std_cmd_table[i].name, NULL);
421 if (rc)
422 return rc;
425 return 0;
430 /* Process the special data lines. The "D " has already been removed
431 from the line. As all handlers this function may modify the line. */
432 static int
433 handle_data_line (assuan_context_t ctx, char *line, int linelen)
435 return set_error (ctx, Not_Implemented, NULL);
438 /* like ascii_strcasecmp but assume that B is already uppercase */
439 static int
440 my_strcasecmp (const char *a, const char *b)
442 if (a == b)
443 return 0;
445 for (; *a && *b; a++, b++)
447 if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
448 break;
450 return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
454 /* Parse the line, break out the command, find it in the command
455 table, remove leading and white spaces from the arguments, call the
456 handler with the argument line and return the error. */
457 static int
458 dispatch_command (assuan_context_t ctx, char *line, int linelen)
460 char *p;
461 const char *s;
462 int shift, i;
463 int rc;
465 /* Note that as this function is invoked by assuan_process_next as
466 well, we need to hide non-critical errors with PROCESS_DONE. */
468 if (*line == 'D' && line[1] == ' ') /* divert to special handler */
469 /* FIXME: Depending on the final implementation of
470 handle_data_line, this may be wrong here. For example, if a
471 user callback is invoked, and that callback is responsible for
472 calling assuan_process_done, then this is wrong. */
473 return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));
475 for (p=line; *p && *p != ' ' && *p != '\t'; p++)
477 if (p==line)
478 return PROCESS_DONE
479 (ctx, set_error (ctx, Syntax_Error, "leading white-space"));
480 if (*p)
481 { /* Skip over leading WS after the keyword */
482 *p++ = 0;
483 while ( *p == ' ' || *p == '\t')
484 p++;
486 shift = p - line;
488 for (i=0; (s=ctx->cmdtbl[i].name); i++)
490 if (!strcmp (line, s))
491 break;
493 if (!s)
494 { /* and try case insensitive */
495 for (i=0; (s=ctx->cmdtbl[i].name); i++)
497 if (!my_strcasecmp (line, s))
498 break;
501 if (!s)
502 return PROCESS_DONE (ctx, set_error (ctx, Unknown_Command, NULL));
503 line += shift;
504 linelen -= shift;
506 if (ctx->pre_cmd_notify_fnc) {
507 rc = ctx->pre_cmd_notify_fnc(ctx, ctx->cmdtbl[i].name);
509 if (rc)
510 return PROCESS_DONE (ctx, rc);
513 /* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
514 return ctx->cmdtbl[i].handler (ctx, line);
518 /* Call this to acknowledge the current command. */
520 assuan_process_done (assuan_context_t ctx, int rc)
522 if (!ctx->in_command)
523 return _assuan_error (ASSUAN_General_Error);
525 ctx->in_command = 0;
527 /* Check for data write errors. */
528 if (ctx->outbound.data.fp)
530 /* Flush the data lines. */
531 fclose (ctx->outbound.data.fp);
532 ctx->outbound.data.fp = NULL;
533 if (!rc && ctx->outbound.data.error)
534 rc = ctx->outbound.data.error;
536 else
538 /* Flush any data send without using the data FP. */
539 assuan_send_data (ctx, NULL, 0);
540 if (!rc && ctx->outbound.data.error)
541 rc = ctx->outbound.data.error;
544 /* Error handling. */
545 if (!rc)
547 rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
549 else if (err_is_eof (rc))
550 { /* No error checking because the peer may have already disconnect. */
551 assuan_write_line (ctx, "OK closing connection");
552 ctx->finish_handler (ctx);
554 else
556 char errline[300];
558 if (rc < 100)
559 sprintf (errline, "ERR %d server fault (%.50s)",
560 _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
561 else
563 const char *text = ctx->err_no == rc? ctx->err_str:NULL;
565 #if defined(HAVE_W32_SYSTEM)
566 unsigned int source, code;
567 char ebuf[50];
568 const char *esrc;
570 source = ((rc >> 24) & 0xff);
571 code = (rc & 0x00ffffff);
572 if (source
573 && !_assuan_gpg_strerror_r (rc, ebuf, sizeof ebuf)
574 && (esrc=_assuan_gpg_strsource (rc)))
576 /* Assume this is an libgpg-error. */
577 sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
578 rc, ebuf, esrc,
579 text? " - ":"", text?text:"");
581 else
582 #elif defined(__GNUC__) && defined(__ELF__)
583 /* If we have weak symbol support we try to use the error
584 strings from libgpg-error without creating a dependency.
585 They are used for debugging purposes only, so there is no
586 problem if they are not available. We need to make sure
587 that we are using ELF because only this guarantees that
588 weak symbol support is available in case GNU ld is not
589 used. It seems that old gcc versions don't implement the
590 weak attribute properly but it works with the weak
591 pragma. */
593 unsigned int source, code;
595 int gpg_strerror_r (unsigned int err, char *buf, size_t buflen)
596 __attribute__ ((weak));
597 const char *gpg_strsource (unsigned int err)
598 __attribute__ ((weak));
599 #if __GNUC__ < 3
600 #pragma weak gpg_strerror_r
601 #pragma weak gpg_strsource
602 #endif
604 source = ((rc >> 24) & 0xff);
605 code = (rc & 0x00ffffff);
606 if (source && gpg_strsource && gpg_strerror_r)
608 /* Assume this is an libgpg-error. */
609 char ebuf[50];
611 gpg_strerror_r (rc, ebuf, sizeof ebuf );
612 sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
614 ebuf,
615 gpg_strsource (rc),
616 text? " - ":"", text?text:"");
618 else
619 #endif /* __GNUC__ && __ELF__ */
620 sprintf (errline, "ERR %d %.50s%s%.100s",
621 rc, assuan_strerror (rc), text? " - ":"", text?text:"");
623 rc = assuan_write_line (ctx, errline);
626 if (ctx->post_cmd_notify_fnc)
627 ctx->post_cmd_notify_fnc (ctx, rc);
629 ctx->confidential = 0;
630 if (ctx->okay_line)
632 xfree (ctx->okay_line);
633 ctx->okay_line = NULL;
636 return rc;
640 static int
641 process_next (assuan_context_t ctx)
643 int rc;
645 /* What the next thing to do is depends on the current state.
646 However, we will always first read the next line. The client is
647 required to write full lines without blocking long after starting
648 a partial line. */
649 rc = _assuan_read_line (ctx);
650 if (_assuan_error_is_eagain (rc))
651 return 0;
652 if (rc)
653 return rc;
654 if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
655 /* Comment lines are ignored. */
656 return 0;
658 /* Now we have a line that really means something. It could be one
659 of the following things: First, if we are not in a command
660 already, it is the next command to dispatch. Second, if we are
661 in a command, it can only be the response to an INQUIRE
662 reply. */
664 if (!ctx->in_command)
666 ctx->in_command = 1;
668 ctx->outbound.data.error = 0;
669 ctx->outbound.data.linelen = 0;
670 /* Dispatch command and return reply. */
671 ctx->in_process_next = 1;
672 rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
673 ctx->in_process_next = 0;
675 else if (ctx->in_inquire)
677 /* FIXME: Pick up the continuation. */
678 rc = _assuan_inquire_ext_cb (ctx);
680 else
682 /* Should not happen. The client is sending data while we are
683 in a command and not waiting for an inquire. We log an error
684 and discard it. */
685 _assuan_log_printf ("unexpected client data\n");
686 rc = 0;
689 return rc;
693 /* This function should be invoked when the assuan connected FD is
694 ready for reading. If the equivalent to EWOULDBLOCK is returned
695 (this should be done by the command handler), assuan_process_next
696 should be invoked the next time the connected FD is readable.
697 Eventually, the caller will finish by invoking
698 assuan_process_done. */
699 int
700 assuan_process_next (assuan_context_t ctx)
702 int rc;
706 rc = process_next (ctx);
708 while (!rc && assuan_pending_line (ctx));
710 return rc;
715 static int
716 process_request (assuan_context_t ctx)
718 int rc;
720 if (ctx->in_inquire)
721 return _assuan_error (ASSUAN_Nested_Commands);
725 rc = _assuan_read_line (ctx);
727 while (_assuan_error_is_eagain (rc));
728 if (rc)
729 return rc;
730 if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
731 return 0; /* comment line - ignore */
733 ctx->in_command = 1;
734 ctx->outbound.data.error = 0;
735 ctx->outbound.data.linelen = 0;
736 /* dispatch command and return reply */
737 rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
739 return assuan_process_done (ctx, rc);
743 * assuan_process:
744 * @ctx: assuan context
746 * This function is used to handle the assuan protocol after a
747 * connection has been established using assuan_accept(). This is the
748 * main protocol handler.
750 * Return value: 0 on success or an error code if the assuan operation
751 * failed. Note, that no error is returned for operational errors.
754 assuan_process (assuan_context_t ctx)
756 int rc;
758 do {
759 rc = process_request (ctx);
760 } while (!rc);
762 if (err_is_eof (rc))
763 rc = 0;
765 return rc;
770 * assuan_get_active_fds:
771 * @ctx: Assuan context
772 * @what: 0 for read fds, 1 for write fds
773 * @fdarray: Caller supplied array to store the FDs
774 * @fdarraysize: size of that array
776 * Return all active filedescriptors for the given context. This
777 * function can be used to select on the fds and call
778 * assuan_process_next() if there is an active one. The first fd in
779 * the array is the one used for the command connection.
781 * Note, that write FDs are not yet supported.
783 * Return value: number of FDs active and put into @fdarray or -1 on
784 * error which is most likely a too small fdarray.
786 int
787 assuan_get_active_fds (assuan_context_t ctx, int what,
788 assuan_fd_t *fdarray, int fdarraysize)
790 int n = 0;
792 if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
793 return -1;
795 if (!what)
797 if (ctx->inbound.fd != ASSUAN_INVALID_FD)
798 fdarray[n++] = ctx->inbound.fd;
800 else
802 if (ctx->outbound.fd != ASSUAN_INVALID_FD)
803 fdarray[n++] = ctx->outbound.fd;
804 if (ctx->outbound.data.fp)
805 #ifdef HAVE_W32_SYSTEM
806 fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp));
807 #else
808 fdarray[n++] = fileno (ctx->outbound.data.fp);
809 #endif
812 return n;
816 /* Two simple wrappers to make the expected function types match. */
817 #ifdef HAVE_FUNOPEN
818 static int
819 fun1_cookie_write (void *cookie, const char *buffer, int orig_size)
821 return _assuan_cookie_write_data (cookie, buffer, orig_size);
823 #endif /*HAVE_FUNOPEN*/
824 #ifdef HAVE_FOPENCOOKIE
825 static ssize_t
826 fun2_cookie_write (void *cookie, const char *buffer, size_t orig_size)
828 return _assuan_cookie_write_data (cookie, buffer, orig_size);
830 #endif /*HAVE_FOPENCOOKIE*/
832 /* Return a FP to be used for data output. The FILE pointer is valid
833 until the end of a handler. So a close is not needed. Assuan does
834 all the buffering needed to insert the status line as well as the
835 required line wappping and quoting for data lines.
837 We use GNU's custom streams here. There should be an alternative
838 implementaion for systems w/o a glibc, a simple implementation
839 could use a child process */
840 FILE *
841 assuan_get_data_fp (assuan_context_t ctx)
843 #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
844 if (ctx->outbound.data.fp)
845 return ctx->outbound.data.fp;
847 #ifdef HAVE_FUNOPEN
848 ctx->outbound.data.fp = funopen (ctx, 0, fun1_cookie_write,
849 0, _assuan_cookie_write_flush);
850 #else
851 ctx->outbound.data.fp = funopen (ctx, 0, fun2_cookie_write,
852 0, _assuan_cookie_write_flush);
853 #endif
855 ctx->outbound.data.error = 0;
856 return ctx->outbound.data.fp;
857 #else
858 errno = ENOSYS;
859 return NULL;
860 #endif
864 /* Set the text used for the next OK reponse. This string is
865 automatically reset to NULL after the next command. */
866 assuan_error_t
867 assuan_set_okay_line (assuan_context_t ctx, const char *line)
869 if (!ctx)
870 return _assuan_error (ASSUAN_Invalid_Value);
871 if (!line)
873 xfree (ctx->okay_line);
874 ctx->okay_line = NULL;
876 else
878 /* FIXME: we need to use gcry_is_secure() to test whether
879 we should allocate the entire line in secure memory */
880 char *buf = xtrymalloc (3+strlen(line)+1);
881 if (!buf)
882 return _assuan_error (ASSUAN_Out_Of_Core);
883 strcpy (buf, "OK ");
884 strcpy (buf+3, line);
885 xfree (ctx->okay_line);
886 ctx->okay_line = buf;
888 return 0;
893 assuan_error_t
894 assuan_write_status (assuan_context_t ctx,
895 const char *keyword, const char *text)
897 char buffer[256];
898 char *helpbuf;
899 size_t n;
900 assuan_error_t ae;
902 if ( !ctx || !keyword)
903 return _assuan_error (ASSUAN_Invalid_Value);
904 if (!text)
905 text = "";
907 n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
908 if (n < sizeof (buffer))
910 strcpy (buffer, "S ");
911 strcat (buffer, keyword);
912 if (*text)
914 strcat (buffer, " ");
915 strcat (buffer, text);
917 ae = assuan_write_line (ctx, buffer);
919 else if ( (helpbuf = xtrymalloc (n)) )
921 strcpy (helpbuf, "S ");
922 strcat (helpbuf, keyword);
923 if (*text)
925 strcat (helpbuf, " ");
926 strcat (helpbuf, text);
928 ae = assuan_write_line (ctx, helpbuf);
929 xfree (helpbuf);
931 else
932 ae = 0;
933 return ae;