1 /* asshelp2.c - More helper functions for Assuan
2  * Copyright (C) 2012 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29 
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <assuan.h>
36 
37 #include "util.h"
38 #include "asshelp.h"
39 #include "status.h"
40 
41 
42 /* A variable with a function to be used to return the current assuan
43  * context for a CTRL variable.  This needs to be set using the
44  * set_assuan_ctx_func function.  */
45 static assuan_context_t (*the_assuan_ctx_func)(ctrl_t ctrl);
46 
47 
48 /* Set FUNC to be used as a mapping function from CTRL to an assuan
49  * context.  Pass NULL for FUNC to disable the use of the assuan
50  * context in this module.  */
51 void
set_assuan_context_func(assuan_context_t (* func)(ctrl_t ctrl))52 set_assuan_context_func (assuan_context_t (*func)(ctrl_t ctrl))
53 {
54   the_assuan_ctx_func = func;
55 }
56 
57 
58 /* Helper function to print an assuan status line using a printf
59    format string.  */
60 gpg_error_t
vprint_assuan_status(assuan_context_t ctx,const char * keyword,const char * format,va_list arg_ptr)61 vprint_assuan_status (assuan_context_t ctx,
62                       const char *keyword,
63                       const char *format, va_list arg_ptr)
64 {
65   int rc;
66   char *buf;
67 
68   rc = gpgrt_vasprintf (&buf, format, arg_ptr);
69   if (rc < 0)
70     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
71   rc = assuan_write_status (ctx, keyword, buf);
72   xfree (buf);
73   return rc;
74 }
75 
76 
77 /* Helper function to print an assuan status line using a printf
78    format string.  */
79 gpg_error_t
print_assuan_status(assuan_context_t ctx,const char * keyword,const char * format,...)80 print_assuan_status (assuan_context_t ctx,
81                      const char *keyword,
82                      const char *format, ...)
83 {
84   va_list arg_ptr;
85   gpg_error_t err;
86 
87   va_start (arg_ptr, format);
88   err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
89   va_end (arg_ptr);
90   return err;
91 }
92 
93 
94 /* Helper function to print a list of strings as an assuan status
95  * line.  KEYWORD is the first item on the status line.  ARG_PTR is a
96  * list of strings which are all separated by a space in the output.
97  * The last argument must be a NULL.  Linefeeds and carriage returns
98  * characters (which are not allowed in an Assuan status line) are
99  * silently quoted in C-style.  */
100 gpg_error_t
vprint_assuan_status_strings(assuan_context_t ctx,const char * keyword,va_list arg_ptr)101 vprint_assuan_status_strings (assuan_context_t ctx,
102                               const char *keyword, va_list arg_ptr)
103 {
104   gpg_error_t err = 0;
105   const char *text;
106   char buf[950], *p;
107   size_t n;
108 
109   p = buf;
110   n = 0;
111   while ((text = va_arg (arg_ptr, const char *)) && n < DIM (buf)-3 )
112     {
113       if (n)
114         {
115           *p++ = ' ';
116           n++;
117         }
118       for ( ; *text && n < DIM (buf)-3; n++, text++)
119         {
120           if (*text == '\n')
121             {
122               *p++ = '\\';
123               *p++ = 'n';
124               n++;
125             }
126           else if (*text == '\r')
127             {
128               *p++ = '\\';
129               *p++ = 'r';
130               n++;
131             }
132           else
133             *p++ = *text;
134         }
135     }
136   *p = 0;
137   err = assuan_write_status (ctx, keyword, buf);
138 
139   return err;
140 }
141 
142 
143 /* See vprint_assuan_status_strings.  */
144 gpg_error_t
print_assuan_status_strings(assuan_context_t ctx,const char * keyword,...)145 print_assuan_status_strings (assuan_context_t ctx, const char *keyword, ...)
146 {
147   va_list arg_ptr;
148   gpg_error_t err;
149 
150   va_start (arg_ptr, keyword);
151   err = vprint_assuan_status_strings (ctx, keyword, arg_ptr);
152   va_end (arg_ptr);
153   return err;
154 }
155 
156 
157 /* This function is similar to print_assuan_status but takes a CTRL
158  * arg instead of an assuan context as first argument.  */
159 gpg_error_t
status_printf(ctrl_t ctrl,const char * keyword,const char * format,...)160 status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
161 {
162   gpg_error_t err;
163   va_list arg_ptr;
164   assuan_context_t ctx;
165 
166   if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
167     return 0;
168 
169   va_start (arg_ptr, format);
170   err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
171   va_end (arg_ptr);
172   return err;
173 }
174 
175 
176 /* Same as status_printf but takes a status number instead of a
177  * keyword.  */
178 gpg_error_t
status_no_printf(ctrl_t ctrl,int no,const char * format,...)179 status_no_printf (ctrl_t ctrl, int no, const char *format, ...)
180 {
181   gpg_error_t err;
182   va_list arg_ptr;
183   assuan_context_t ctx;
184 
185   if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
186     return 0;
187 
188   va_start (arg_ptr, format);
189   err = vprint_assuan_status (ctx, get_status_string (no), format, arg_ptr);
190   va_end (arg_ptr);
191   return err;
192 }
193