03c7c099ab0aad16caac61f98afa4aceaeae7a32
[gnupg.git] / assuan / assuan-client.c
1 /* assuan-client.c - client functions
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <assert.h>
27
28 #include "assuan-defs.h"
29
30 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
31                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
32 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
33
34
35 static AssuanError
36 read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
37 {
38   char *line;
39   int linelen;
40   AssuanError rc;
41
42   *okay = 0;
43   *off = 0;
44   do 
45     {
46       rc = _assuan_read_line (ctx);
47       if (rc)
48         return rc;
49       line = ctx->inbound.line;
50       linelen = ctx->inbound.linelen;
51     }    
52   while (*line == '#' || !linelen);
53
54   if (linelen >= 1
55       && line[0] == 'D' && line[1] == ' ')
56     {
57       *okay = 2; /* data line */
58       *off = 2;
59     }
60   else if (linelen >= 2
61            && line[0] == 'O' && line[1] == 'K'
62            && (line[2] == '\0' || line[2] == ' '))
63     {
64       *okay = 1;
65       *off = 2;
66     }
67   else if (linelen >= 3
68            && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
69            && (line[3] == '\0' || line[3] == ' '))
70     {
71       *okay = 0;
72       *off = 3;
73     }  
74   else if (linelen >= 7
75            && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
76            && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
77            && line[6] == 'E' 
78            && (line[7] == '\0' || line[7] == ' '))
79     {
80       *okay = 3;
81       *off = 7;
82     }
83   else
84     rc = ASSUAN_Invalid_Response;
85   return rc;
86 }
87
88
89 \f
90 /**
91  * assuan_transact:
92  * @ctx: The Assuan context
93  * @command: Coimmand line to be send to server
94  * @data_cb: Callback function for data lines
95  * @data_cb_arg: first argument passed to @data_cb
96  * @inquire_cb: Callback function for a inquire response
97  * @inquire_cb_arg: first argument passed to @inquire_cb
98  * 
99  * FIXME: Write documentation
100  * 
101  * Return value: 0 on success or error code.  The error code may be
102  * the one one returned by the server in error lines or from the
103  * callback functions.
104  **/
105 AssuanError
106 assuan_transact (ASSUAN_CONTEXT ctx,
107                  const char *command,
108                  AssuanError (*data_cb)(void *, const void *, size_t),
109                  void *data_cb_arg,
110                  AssuanError (*inquire_cb)(void*, const char *),
111                  void *inquire_cb_arg)
112 {
113   int rc, okay, off;
114   unsigned char *line;
115   int linelen;
116
117   rc = _assuan_write_line (ctx, command);
118   if (rc)
119     return rc;
120
121  again:
122   rc = read_from_server (ctx, &okay, &off);
123   if (rc)
124     return rc; /* error reading from server */
125
126   line = ctx->inbound.line + off;
127   linelen = ctx->inbound.linelen - off;
128
129   if (!okay)
130     {
131       rc = atoi (line);
132       if (rc < 100)
133         rc = ASSUAN_Server_Fault;
134     }
135   else if (okay == 2)
136     {
137       if (!data_cb)
138         rc = ASSUAN_No_Data_Callback;
139       else 
140         {
141           unsigned char *s, *d;
142
143           for (s=d=line; linelen; linelen--)
144             {
145               if (*s == '%' && linelen > 2)
146                 { /* handle escaping */
147                   s++;
148                   *d++ = xtoi_2 (s);
149                   s += 2;
150                   linelen -= 2;
151                 }
152               else
153                 *d++ = *s++;
154             }
155           *d = 0; /* add a hidden string terminator */
156           rc = data_cb (data_cb_arg, line, d - line);
157           if (!rc)
158             goto again;
159         }
160     }
161   else if (okay == 3)
162     {
163       if (!inquire_cb)
164         {
165           _assuan_write_line (ctx, "END"); /* get out of inquire mode */
166           read_from_server (ctx, &okay, &off); /* dummy read the response */
167           rc = ASSUAN_No_Inquire_Callback;
168         }
169       else
170         {
171           rc = inquire_cb (inquire_cb_arg, line);
172           if (!rc)
173             rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
174           if (!rc)
175             goto again;
176         }
177     }
178
179   return rc;
180 }