Call libssh2_channel_close() before freeing it.
[libpwmd.git] / assuan / assuan-handler.c
blobb940bfd42836ee3ed0d86c21f91fd74ad91683ff
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 { "OPTION", std_handler_option, 1 },
257 { NULL, NULL, 0 }
262 * assuan_register_command:
263 * @ctx: the server context
264 * @cmd_name: A string with the command name
265 * @handler: The handler function to be called or NULL to use a default
266 * handler.
268 * Register a handler to be used for a given command. Note that
269 * several default handlers are already regsitered with a new context.
270 * This function however allows to override them.
272 * Return value: 0 on success or an error code
275 assuan_register_command (assuan_context_t ctx,
276 const char *cmd_name,
277 int (*handler)(assuan_context_t, char *))
279 int i;
280 const char *s;
282 if (cmd_name && !*cmd_name)
283 cmd_name = NULL;
285 if (!cmd_name)
286 return _assuan_error (ASSUAN_Invalid_Value);
288 if (!handler)
289 { /* find a default handler. */
290 for (i=0; (s=std_cmd_table[i].name) && strcmp (cmd_name, s); i++)
292 if (!s)
293 { /* Try again but case insensitive. */
294 for (i=0; (s=std_cmd_table[i].name)
295 && my_strcasecmp (cmd_name, s); i++)
298 if (s)
299 handler = std_cmd_table[i].handler;
300 if (!handler)
301 handler = dummy_handler; /* Last resort is the dummy handler. */
304 if (!ctx->cmdtbl)
306 ctx->cmdtbl_size = 50;
307 ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
308 if (!ctx->cmdtbl)
309 return _assuan_error (ASSUAN_Out_Of_Core);
310 ctx->cmdtbl_used = 0;
312 else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
314 struct cmdtbl_s *x;
316 x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
317 if (!x)
318 return _assuan_error (ASSUAN_Out_Of_Core);
319 ctx->cmdtbl = x;
320 ctx->cmdtbl_size += 50;
323 ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
324 ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
325 ctx->cmdtbl_used++;
326 return 0;
330 assuan_register_post_cmd_notify (assuan_context_t ctx,
331 void (*fnc)(assuan_context_t, int))
333 if (!ctx)
334 return _assuan_error (ASSUAN_Invalid_Value);
335 ctx->post_cmd_notify_fnc = fnc;
336 return 0;
340 assuan_register_bye_notify (assuan_context_t ctx,
341 void (*fnc)(assuan_context_t))
343 if (!ctx)
344 return _assuan_error (ASSUAN_Invalid_Value);
345 ctx->bye_notify_fnc = fnc;
346 return 0;
350 assuan_register_reset_notify (assuan_context_t ctx,
351 void (*fnc)(assuan_context_t))
353 if (!ctx)
354 return _assuan_error (ASSUAN_Invalid_Value);
355 ctx->reset_notify_fnc = fnc;
356 return 0;
360 assuan_register_cancel_notify (assuan_context_t ctx,
361 void (*fnc)(assuan_context_t))
363 if (!ctx)
364 return _assuan_error (ASSUAN_Invalid_Value);
365 ctx->cancel_notify_fnc = fnc;
366 return 0;
370 assuan_register_option_handler (assuan_context_t ctx,
371 int (*fnc)(assuan_context_t,
372 const char*, const char*))
374 if (!ctx)
375 return _assuan_error (ASSUAN_Invalid_Value);
376 ctx->option_handler_fnc = fnc;
377 return 0;
381 assuan_register_input_notify (assuan_context_t ctx,
382 void (*fnc)(assuan_context_t, const char *))
384 if (!ctx)
385 return _assuan_error (ASSUAN_Invalid_Value);
386 ctx->input_notify_fnc = fnc;
387 return 0;
391 assuan_register_output_notify (assuan_context_t ctx,
392 void (*fnc)(assuan_context_t, const char *))
394 if (!ctx)
395 return _assuan_error (ASSUAN_Invalid_Value);
396 ctx->output_notify_fnc = fnc;
397 return 0;
401 /* Helper to register the standards commands */
403 _assuan_register_std_commands (assuan_context_t ctx)
405 int i, rc;
407 for (i=0; std_cmd_table[i].name; i++)
409 if (std_cmd_table[i].always)
411 rc = assuan_register_command (ctx, std_cmd_table[i].name, NULL);
412 if (rc)
413 return rc;
416 return 0;
421 /* Process the special data lines. The "D " has already been removed
422 from the line. As all handlers this function may modify the line. */
423 static int
424 handle_data_line (assuan_context_t ctx, char *line, int linelen)
426 return set_error (ctx, Not_Implemented, NULL);
429 /* like ascii_strcasecmp but assume that B is already uppercase */
430 static int
431 my_strcasecmp (const char *a, const char *b)
433 if (a == b)
434 return 0;
436 for (; *a && *b; a++, b++)
438 if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
439 break;
441 return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
445 /* Parse the line, break out the command, find it in the command
446 table, remove leading and white spaces from the arguments, call the
447 handler with the argument line and return the error. */
448 static int
449 dispatch_command (assuan_context_t ctx, char *line, int linelen)
451 char *p;
452 const char *s;
453 int shift, i;
455 /* Note that as this function is invoked by assuan_process_next as
456 well, we need to hide non-critical errors with PROCESS_DONE. */
458 if (*line == 'D' && line[1] == ' ') /* divert to special handler */
459 /* FIXME: Depending on the final implementation of
460 handle_data_line, this may be wrong here. For example, if a
461 user callback is invoked, and that callback is responsible for
462 calling assuan_process_done, then this is wrong. */
463 return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));
465 for (p=line; *p && *p != ' ' && *p != '\t'; p++)
467 if (p==line)
468 return PROCESS_DONE
469 (ctx, set_error (ctx, Syntax_Error, "leading white-space"));
470 if (*p)
471 { /* Skip over leading WS after the keyword */
472 *p++ = 0;
473 while ( *p == ' ' || *p == '\t')
474 p++;
476 shift = p - line;
478 for (i=0; (s=ctx->cmdtbl[i].name); i++)
480 if (!strcmp (line, s))
481 break;
483 if (!s)
484 { /* and try case insensitive */
485 for (i=0; (s=ctx->cmdtbl[i].name); i++)
487 if (!my_strcasecmp (line, s))
488 break;
491 if (!s)
492 return PROCESS_DONE (ctx, set_error (ctx, Unknown_Command, NULL));
493 line += shift;
494 linelen -= shift;
496 /* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
497 return ctx->cmdtbl[i].handler (ctx, line);
501 /* Call this to acknowledge the current command. */
503 assuan_process_done (assuan_context_t ctx, int rc)
505 if (!ctx->in_command)
506 return _assuan_error (ASSUAN_General_Error);
508 ctx->in_command = 0;
510 /* Check for data write errors. */
511 if (ctx->outbound.data.fp)
513 /* Flush the data lines. */
514 fclose (ctx->outbound.data.fp);
515 ctx->outbound.data.fp = NULL;
516 if (!rc && ctx->outbound.data.error)
517 rc = ctx->outbound.data.error;
519 else
521 /* Flush any data send without using the data FP. */
522 assuan_send_data (ctx, NULL, 0);
523 if (!rc && ctx->outbound.data.error)
524 rc = ctx->outbound.data.error;
527 /* Error handling. */
528 if (!rc)
530 rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
532 else if (err_is_eof (rc))
533 { /* No error checking because the peer may have already disconnect. */
534 assuan_write_line (ctx, "OK closing connection");
535 ctx->finish_handler (ctx);
537 else
539 char errline[300];
541 if (rc < 100)
542 sprintf (errline, "ERR %d server fault (%.50s)",
543 _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
544 else
546 const char *text = ctx->err_no == rc? ctx->err_str:NULL;
548 #if defined(HAVE_W32_SYSTEM)
549 unsigned int source, code;
550 char ebuf[50];
551 const char *esrc;
553 source = ((rc >> 24) & 0xff);
554 code = (rc & 0x00ffffff);
555 if (source
556 && !_assuan_gpg_strerror_r (rc, ebuf, sizeof ebuf)
557 && (esrc=_assuan_gpg_strsource (rc)))
559 /* Assume this is an libgpg-error. */
560 sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
561 rc, ebuf, esrc,
562 text? " - ":"", text?text:"");
564 else
565 #elif defined(__GNUC__) && defined(__ELF__)
566 /* If we have weak symbol support we try to use the error
567 strings from libgpg-error without creating a dependency.
568 They are used for debugging purposes only, so there is no
569 problem if they are not available. We need to make sure
570 that we are using ELF because only this guarantees that
571 weak symbol support is available in case GNU ld is not
572 used. It seems that old gcc versions don't implement the
573 weak attribute properly but it works with the weak
574 pragma. */
576 unsigned int source, code;
578 int gpg_strerror_r (unsigned int err, char *buf, size_t buflen)
579 __attribute__ ((weak));
580 const char *gpg_strsource (unsigned int err)
581 __attribute__ ((weak));
582 #if __GNUC__ < 3
583 #pragma weak gpg_strerror_r
584 #pragma weak gpg_strsource
585 #endif
587 source = ((rc >> 24) & 0xff);
588 code = (rc & 0x00ffffff);
589 if (source && gpg_strsource && gpg_strerror_r)
591 /* Assume this is an libgpg-error. */
592 char ebuf[50];
594 gpg_strerror_r (rc, ebuf, sizeof ebuf );
595 sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
597 ebuf,
598 gpg_strsource (rc),
599 text? " - ":"", text?text:"");
601 else
602 #endif /* __GNUC__ && __ELF__ */
603 sprintf (errline, "ERR %d %.50s%s%.100s",
604 rc, assuan_strerror (rc), text? " - ":"", text?text:"");
606 rc = assuan_write_line (ctx, errline);
609 if (ctx->post_cmd_notify_fnc)
610 ctx->post_cmd_notify_fnc (ctx, rc);
612 ctx->confidential = 0;
613 if (ctx->okay_line)
615 xfree (ctx->okay_line);
616 ctx->okay_line = NULL;
619 return rc;
623 static int
624 process_next (assuan_context_t ctx)
626 int rc;
628 /* What the next thing to do is depends on the current state.
629 However, we will always first read the next line. The client is
630 required to write full lines without blocking long after starting
631 a partial line. */
632 rc = _assuan_read_line (ctx);
633 if (_assuan_error_is_eagain (rc))
634 return 0;
635 if (rc)
636 return rc;
637 if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
638 /* Comment lines are ignored. */
639 return 0;
641 /* Now we have a line that really means something. It could be one
642 of the following things: First, if we are not in a command
643 already, it is the next command to dispatch. Second, if we are
644 in a command, it can only be the response to an INQUIRE
645 reply. */
647 if (!ctx->in_command)
649 ctx->in_command = 1;
651 ctx->outbound.data.error = 0;
652 ctx->outbound.data.linelen = 0;
653 /* Dispatch command and return reply. */
654 ctx->in_process_next = 1;
655 rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
656 ctx->in_process_next = 0;
658 else if (ctx->in_inquire)
660 /* FIXME: Pick up the continuation. */
661 rc = _assuan_inquire_ext_cb (ctx);
663 else
665 /* Should not happen. The client is sending data while we are
666 in a command and not waiting for an inquire. We log an error
667 and discard it. */
668 _assuan_log_printf ("unexpected client data\n");
669 rc = 0;
672 return rc;
676 /* This function should be invoked when the assuan connected FD is
677 ready for reading. If the equivalent to EWOULDBLOCK is returned
678 (this should be done by the command handler), assuan_process_next
679 should be invoked the next time the connected FD is readable.
680 Eventually, the caller will finish by invoking
681 assuan_process_done. */
682 int
683 assuan_process_next (assuan_context_t ctx)
685 int rc;
689 rc = process_next (ctx);
691 while (!rc && assuan_pending_line (ctx));
693 return rc;
698 static int
699 process_request (assuan_context_t ctx)
701 int rc;
703 if (ctx->in_inquire)
704 return _assuan_error (ASSUAN_Nested_Commands);
708 rc = _assuan_read_line (ctx);
710 while (_assuan_error_is_eagain (rc));
711 if (rc)
712 return rc;
713 if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
714 return 0; /* comment line - ignore */
716 ctx->in_command = 1;
717 ctx->outbound.data.error = 0;
718 ctx->outbound.data.linelen = 0;
719 /* dispatch command and return reply */
720 rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
722 return assuan_process_done (ctx, rc);
726 * assuan_process:
727 * @ctx: assuan context
729 * This function is used to handle the assuan protocol after a
730 * connection has been established using assuan_accept(). This is the
731 * main protocol handler.
733 * Return value: 0 on success or an error code if the assuan operation
734 * failed. Note, that no error is returned for operational errors.
737 assuan_process (assuan_context_t ctx)
739 int rc;
741 do {
742 rc = process_request (ctx);
743 } while (!rc);
745 if (err_is_eof (rc))
746 rc = 0;
748 return rc;
753 * assuan_get_active_fds:
754 * @ctx: Assuan context
755 * @what: 0 for read fds, 1 for write fds
756 * @fdarray: Caller supplied array to store the FDs
757 * @fdarraysize: size of that array
759 * Return all active filedescriptors for the given context. This
760 * function can be used to select on the fds and call
761 * assuan_process_next() if there is an active one. The first fd in
762 * the array is the one used for the command connection.
764 * Note, that write FDs are not yet supported.
766 * Return value: number of FDs active and put into @fdarray or -1 on
767 * error which is most likely a too small fdarray.
769 int
770 assuan_get_active_fds (assuan_context_t ctx, int what,
771 assuan_fd_t *fdarray, int fdarraysize)
773 int n = 0;
775 if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
776 return -1;
778 if (!what)
780 if (ctx->inbound.fd != ASSUAN_INVALID_FD)
781 fdarray[n++] = ctx->inbound.fd;
783 else
785 if (ctx->outbound.fd != ASSUAN_INVALID_FD)
786 fdarray[n++] = ctx->outbound.fd;
787 if (ctx->outbound.data.fp)
788 #ifdef HAVE_W32_SYSTEM
789 fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp));
790 #else
791 fdarray[n++] = fileno (ctx->outbound.data.fp);
792 #endif
795 return n;
799 /* Two simple wrappers to make the expected function types match. */
800 #ifdef HAVE_FUNOPEN
801 static int
802 fun1_cookie_write (void *cookie, const char *buffer, int orig_size)
804 return _assuan_cookie_write_data (cookie, buffer, orig_size);
806 #endif /*HAVE_FUNOPEN*/
807 #ifdef HAVE_FOPENCOOKIE
808 static ssize_t
809 fun2_cookie_write (void *cookie, const char *buffer, size_t orig_size)
811 return _assuan_cookie_write_data (cookie, buffer, orig_size);
813 #endif /*HAVE_FOPENCOOKIE*/
815 /* Return a FP to be used for data output. The FILE pointer is valid
816 until the end of a handler. So a close is not needed. Assuan does
817 all the buffering needed to insert the status line as well as the
818 required line wappping and quoting for data lines.
820 We use GNU's custom streams here. There should be an alternative
821 implementaion for systems w/o a glibc, a simple implementation
822 could use a child process */
823 FILE *
824 assuan_get_data_fp (assuan_context_t ctx)
826 #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
827 if (ctx->outbound.data.fp)
828 return ctx->outbound.data.fp;
830 #ifdef HAVE_FUNOPEN
831 ctx->outbound.data.fp = funopen (ctx, 0, fun1_cookie_write,
832 0, _assuan_cookie_write_flush);
833 #else
834 ctx->outbound.data.fp = funopen (ctx, 0, fun2_cookie_write,
835 0, _assuan_cookie_write_flush);
836 #endif
838 ctx->outbound.data.error = 0;
839 return ctx->outbound.data.fp;
840 #else
841 errno = ENOSYS;
842 return NULL;
843 #endif
847 /* Set the text used for the next OK reponse. This string is
848 automatically reset to NULL after the next command. */
849 assuan_error_t
850 assuan_set_okay_line (assuan_context_t ctx, const char *line)
852 if (!ctx)
853 return _assuan_error (ASSUAN_Invalid_Value);
854 if (!line)
856 xfree (ctx->okay_line);
857 ctx->okay_line = NULL;
859 else
861 /* FIXME: we need to use gcry_is_secure() to test whether
862 we should allocate the entire line in secure memory */
863 char *buf = xtrymalloc (3+strlen(line)+1);
864 if (!buf)
865 return _assuan_error (ASSUAN_Out_Of_Core);
866 strcpy (buf, "OK ");
867 strcpy (buf+3, line);
868 xfree (ctx->okay_line);
869 ctx->okay_line = buf;
871 return 0;
876 assuan_error_t
877 assuan_write_status (assuan_context_t ctx,
878 const char *keyword, const char *text)
880 char buffer[256];
881 char *helpbuf;
882 size_t n;
883 assuan_error_t ae;
885 if ( !ctx || !keyword)
886 return _assuan_error (ASSUAN_Invalid_Value);
887 if (!text)
888 text = "";
890 n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
891 if (n < sizeof (buffer))
893 strcpy (buffer, "S ");
894 strcat (buffer, keyword);
895 if (*text)
897 strcat (buffer, " ");
898 strcat (buffer, text);
900 ae = assuan_write_line (ctx, buffer);
902 else if ( (helpbuf = xtrymalloc (n)) )
904 strcpy (helpbuf, "S ");
905 strcat (helpbuf, keyword);
906 if (*text)
908 strcat (helpbuf, " ");
909 strcat (helpbuf, text);
911 ae = assuan_write_line (ctx, helpbuf);
912 xfree (helpbuf);
914 else
915 ae = 0;
916 return ae;