Chnages to supporta pinnetry notification
[gpgme.git] / assuan / assuan-client.c
1 /* assuan-client.c - client functions
2  *      Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of Assuan.
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA. 
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <assert.h>
28
29 #include "assuan-defs.h"
30
31 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
32                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
33 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
34
35
36 assuan_error_t
37 _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
38 {
39   char *line;
40   int linelen;
41   assuan_error_t rc;
42
43   *okay = 0;
44   *off = 0;
45   do 
46     {
47       rc = _assuan_read_line (ctx);
48       if (rc)
49         return rc;
50       line = ctx->inbound.line;
51       linelen = ctx->inbound.linelen;
52     }    
53   while (*line == '#' || !linelen);
54
55   if (linelen >= 1
56       && line[0] == 'D' && line[1] == ' ')
57     {
58       *okay = 2; /* data line */
59       *off = 2;
60     }
61   else if (linelen >= 1
62            && line[0] == 'S' 
63            && (line[1] == '\0' || line[1] == ' '))
64     {
65       *okay = 4;
66       *off = 1;
67       while (line[*off] == ' ')
68         ++*off;
69     }  
70   else if (linelen >= 2
71            && line[0] == 'O' && line[1] == 'K'
72            && (line[2] == '\0' || line[2] == ' '))
73     {
74       *okay = 1;
75       *off = 2;
76       while (line[*off] == ' ')
77         ++*off;
78     }
79   else if (linelen >= 3
80            && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
81            && (line[3] == '\0' || line[3] == ' '))
82     {
83       *okay = 0;
84       *off = 3;
85       while (line[*off] == ' ')
86         ++*off;
87     }  
88   else if (linelen >= 7
89            && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
90            && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
91            && line[6] == 'E' 
92            && (line[7] == '\0' || line[7] == ' '))
93     {
94       *okay = 3;
95       *off = 7;
96       while (line[*off] == ' ')
97         ++*off;
98     }
99   else if (linelen >= 3
100            && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
101            && (line[3] == '\0' || line[3] == ' '))
102     {
103       *okay = 5; /* end line */
104       *off = 3;
105     }
106   else
107     rc = _assuan_error (ASSUAN_Invalid_Response);
108   return rc;
109 }
110
111
112 \f
113 /**
114  * assuan_transact:
115  * @ctx: The Assuan context
116  * @command: Command line to be send to the server
117  * @data_cb: Callback function for data lines
118  * @data_cb_arg: first argument passed to @data_cb
119  * @inquire_cb: Callback function for a inquire response
120  * @inquire_cb_arg: first argument passed to @inquire_cb
121  * @status_cb: Callback function for a status response
122  * @status_cb_arg: first argument passed to @status_cb
123  * 
124  * FIXME: Write documentation
125  * 
126  * Return value: 0 on success or error code.  The error code may be
127  * the one one returned by the server in error lines or from the
128  * callback functions.  Take care: When a callback returns an error
129  * this function returns immediately with an error and thus the caller
130  * will altter return an Assuan error (write erro in most cases).
131  **/
132 assuan_error_t
133 assuan_transact (assuan_context_t ctx,
134                  const char *command,
135                  int (*data_cb)(void *, const void *, size_t),
136                  void *data_cb_arg,
137                  int (*inquire_cb)(void*, const char *),
138                  void *inquire_cb_arg,
139                  int (*status_cb)(void*, const char *),
140                  void *status_cb_arg)
141 {
142   assuan_error_t rc;
143   int okay, off;
144   char *line;
145   int linelen;
146
147   rc = assuan_write_line (ctx, command);
148   if (rc)
149     return rc;
150
151   if (*command == '#' || !*command)
152     return 0; /* Don't expect a response for a comment line.  */
153
154  again:
155   rc = _assuan_read_from_server (ctx, &okay, &off);
156   if (rc)
157     return rc; /* error reading from server */
158
159   line = ctx->inbound.line + off;
160   linelen = ctx->inbound.linelen - off;
161
162   if (!okay)
163     {
164       rc = atoi (line);
165       if (rc > 0 && rc < 100)
166         rc = _assuan_error (ASSUAN_Server_Fault);
167       else if (rc > 0 && rc <= 405)
168         rc = _assuan_error (rc);
169     }
170   else if (okay == 2)
171     {
172       if (!data_cb)
173         rc = _assuan_error (ASSUAN_No_Data_Callback);
174       else 
175         {
176           char *s, *d;
177
178           for (s=d=line; linelen; linelen--)
179             {
180               if (*s == '%' && linelen > 2)
181                 { /* handle escaping */
182                   s++;
183                   *d++ = xtoi_2 (s);
184                   s += 2;
185                   linelen -= 2;
186                 }
187               else
188                 *d++ = *s++;
189             }
190           *d = 0; /* add a hidden string terminator */
191           rc = data_cb (data_cb_arg, line, d - line);
192           if (!rc)
193             goto again;
194         }
195     }
196   else if (okay == 3)
197     {
198       if (!inquire_cb)
199         {
200           assuan_write_line (ctx, "END"); /* get out of inquire mode */
201           _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
202           rc = _assuan_error (ASSUAN_No_Inquire_Callback);
203         }
204       else
205         {
206           rc = inquire_cb (inquire_cb_arg, line);
207           if (!rc)
208             rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
209           if (!rc)
210             goto again;
211         }
212     }
213   else if (okay == 4)
214     {
215       if (status_cb)
216         rc = status_cb (status_cb_arg, line);
217       if (!rc)
218         goto again;
219     }
220   else if (okay == 5)
221     {
222       if (!data_cb)
223         rc = _assuan_error (ASSUAN_No_Data_Callback);
224       else 
225         {
226           rc = data_cb (data_cb_arg, NULL, 0);
227           if (!rc)
228             goto again;
229         }
230     }
231
232   return rc;
233 }
234