* gpgkeys_hkp.c (http_get, http_post): Use CRLF for line endings.
[gnupg.git] / assuan / assuan-buffer.c
1 /* assuan-buffer.c - read and send data
2  *      Copyright (C) 2001, 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <assert.h>
28 #include "assuan-defs.h"
29
30 #ifdef HAVE_JNLIB_LOGGING
31 #include "../jnlib/logging.h"
32 #endif
33
34
35 static const char *
36 my_log_prefix (void)
37 {
38 #ifdef HAVE_JNLIB_LOGGING
39   return log_get_prefix (NULL);
40 #else
41   return "";
42 #endif
43 }
44
45
46 static int
47 writen ( int fd, const char *buffer, size_t length )
48 {
49   while (length)
50     {
51       int nwritten = _assuan_write_wrapper?
52         _assuan_write_wrapper (fd, buffer, length):
53         write (fd, buffer, length);
54       
55       if (nwritten < 0)
56         {
57           if (errno == EINTR)
58             continue;
59           return -1; /* write error */
60         }
61       length -= nwritten;
62       buffer += nwritten;
63     }
64   return 0;  /* okay */
65 }
66
67 /* read an entire line */
68 static int
69 readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
70 {
71   size_t nleft = buflen;
72   char *p;
73
74   *eof = 0;
75   *r_nread = 0;
76   while (nleft > 0)
77     {
78       int n = _assuan_read_wrapper?
79         _assuan_read_wrapper (fd, buf, nleft):
80         read (fd, buf, nleft);
81
82       if (n < 0)
83         {
84           if (errno == EINTR)
85             continue;
86           return -1; /* read error */
87         }
88       else if (!n)
89         {
90           *eof = 1;
91           break; /* allow incomplete lines */
92         }
93       p = buf;
94       nleft -= n;
95       buf += n;
96       *r_nread += n;
97       
98       for (; n && *p != '\n'; n--, p++)
99         ;
100       if (n)
101         break; /* at least one full line available - that's enough for now */
102     }
103
104   return 0;
105 }
106
107
108 int
109 _assuan_read_line (ASSUAN_CONTEXT ctx)
110 {
111   char *line = ctx->inbound.line;
112   int n, nread, atticlen;
113   int rc;
114
115   if (ctx->inbound.eof)
116     return -1;
117
118   atticlen = ctx->inbound.attic.linelen;
119   if (atticlen)
120     {
121       memcpy (line, ctx->inbound.attic.line, atticlen);
122       ctx->inbound.attic.linelen = 0;
123       for (n=0; n < atticlen && line[n] != '\n'; n++)
124         ;
125       if (n < atticlen)
126         {
127           rc = 0; /* found another line in the attic */
128           nread = atticlen;
129           atticlen = 0;
130         }
131       else
132         { /* read the rest */
133           assert (atticlen < LINELENGTH);
134           rc = readline (ctx->inbound.fd, line + atticlen,
135                          LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
136         }
137     }
138   else
139     rc = readline (ctx->inbound.fd, line, LINELENGTH,
140                    &nread, &ctx->inbound.eof);
141   if (rc)
142     {
143       if (ctx->log_fp)
144         fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
145                  my_log_prefix (), ctx, strerror (errno)); 
146       return ASSUAN_Read_Error;
147     }
148   if (!nread)
149     {
150       assert (ctx->inbound.eof);
151       if (ctx->log_fp)
152         fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); 
153       return -1; 
154     }
155
156   ctx->inbound.attic.pending = 0;
157   nread += atticlen;
158   for (n=0; n < nread; n++)
159     {
160       if (line[n] == '\n')
161         {
162           if (n+1 < nread)
163             {
164               char *s, *d;
165               int i;
166
167               n++;
168               /* we have to copy the rest because the handlers are
169                  allowed to modify the passed buffer */
170               for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
171                 {
172                   if (*s=='\n')
173                     ctx->inbound.attic.pending = 1;
174                   *d++ = *s++;
175                 }
176               ctx->inbound.attic.linelen = nread-n;
177               n--;
178             }
179           if (n && line[n-1] == '\r')
180             n--;
181           line[n] = 0;
182           ctx->inbound.linelen = n;
183           if (ctx->log_fp)
184             {
185               fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); 
186               if (ctx->confidential)
187                 fputs ("[Confidential data not shown]", ctx->log_fp);
188               else
189                 _assuan_log_print_buffer (ctx->log_fp, 
190                                           ctx->inbound.line,
191                                           ctx->inbound.linelen);
192               putc ('\n', ctx->log_fp);
193             }
194           return 0;
195         }
196     }
197
198   if (ctx->log_fp)
199     fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
200   *line = 0;
201   ctx->inbound.linelen = 0;
202   return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
203 }
204
205
206 /* Read the next line from the client or server and return a pointer
207    to a buffer with holding that line.  linelen returns the length of
208    the line.  This buffer is valid until another read operation is
209    done on this buffer.  The caller is allowed to modify this buffer.
210    He should only use the buffer if the function returns without an
211    error.
212
213    Returns: 0 on success or an assuan error code
214    See also: assuan_pending_line().
215 */
216 AssuanError
217 assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
218 {
219   AssuanError err;
220
221   if (!ctx)
222     return ASSUAN_Invalid_Value;
223
224   err = _assuan_read_line (ctx);
225   *line = ctx->inbound.line;
226   *linelen = ctx->inbound.linelen;
227   return err;
228 }
229
230
231 /* Return true when a full line is pending for a read, without the need
232    for actual IO */
233 int
234 assuan_pending_line (ASSUAN_CONTEXT ctx)
235 {
236   return ctx && ctx->inbound.attic.pending;
237 }
238
239
240 AssuanError 
241 assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
242 {
243   int rc;
244   size_t len;
245   const char *s;
246
247   if (!ctx)
248     return ASSUAN_Invalid_Value;
249
250   /* Make sure that we never take a LF from the user - this might
251      violate the protocol. */
252   s = strchr (line, '\n');
253   len = s? (s-line) : strlen (line);
254
255   /* fixme: we should do some kind of line buffering.  */
256   if (ctx->log_fp)
257     {
258       fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
259       if (s)
260         fputs ("[supplied line contained a LF]", ctx->log_fp);
261       if (ctx->confidential)
262         fputs ("[Confidential data not shown]", ctx->log_fp);
263       else
264         _assuan_log_print_buffer (ctx->log_fp, line, len);
265       putc ('\n', ctx->log_fp);
266     }
267
268   rc = writen (ctx->outbound.fd, line, len);
269   if (rc)
270     rc = ASSUAN_Write_Error;
271   if (!rc)
272     {
273       rc = writen (ctx->outbound.fd, "\n", 1);
274       if (rc)
275         rc = ASSUAN_Write_Error;
276     }
277
278   return rc;
279 }
280
281
282 \f
283 /* Write out the data in buffer as datalines with line wrapping and
284    percent escaping.  This fucntion is used for GNU's custom streams */
285 int
286 _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
287 {
288   ASSUAN_CONTEXT ctx = cookie;
289   char *line;
290   size_t linelen;
291
292   if (ctx->outbound.data.error)
293     return 0;
294
295   line = ctx->outbound.data.line;
296   linelen = ctx->outbound.data.linelen;
297   line += linelen;
298   while (size)
299     {
300       /* insert data line header */
301       if (!linelen)
302         {
303           *line++ = 'D';
304           *line++ = ' ';
305           linelen += 2;
306         }
307       
308       /* copy data, keep some space for the CRLF and to escape one character */
309       while (size && linelen < LINELENGTH-2-2)
310         {
311           if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
312             {
313               sprintf (line, "%%%02X", *(unsigned char*)buffer);
314               line += 3;
315               linelen += 3;
316               buffer++;
317             }
318           else
319             {
320               *line++ = *buffer++;
321               linelen++;
322             }
323           size--;
324         }
325       
326       if (linelen >= LINELENGTH-2-2)
327         {
328           if (ctx->log_fp)
329             {
330               fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
331               if (ctx->confidential)
332                 fputs ("[Confidential data not shown]", ctx->log_fp);
333               else 
334                 _assuan_log_print_buffer (ctx->log_fp, 
335                                           ctx->outbound.data.line,
336                                           linelen);
337               putc ('\n', ctx->log_fp);
338             }
339           *line++ = '\n';
340           linelen++;
341           if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
342             {
343               ctx->outbound.data.error = ASSUAN_Write_Error;
344               return 0;
345             }
346           line = ctx->outbound.data.line;
347           linelen = 0;
348         }
349     }
350
351   ctx->outbound.data.linelen = linelen;
352   return 0;
353 }
354
355
356 /* Write out any buffered data 
357    This fucntion is used for GNU's custom streams */
358 int
359 _assuan_cookie_write_flush (void *cookie)
360 {
361   ASSUAN_CONTEXT ctx = cookie;
362   char *line;
363   size_t linelen;
364
365   if (ctx->outbound.data.error)
366     return 0;
367
368   line = ctx->outbound.data.line;
369   linelen = ctx->outbound.data.linelen;
370   line += linelen;
371   if (linelen)
372     {
373       if (ctx->log_fp)
374         {
375           fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
376           if (ctx->confidential)
377             fputs ("[Confidential data not shown]", ctx->log_fp);
378           else
379             _assuan_log_print_buffer (ctx->log_fp, 
380                                       ctx->outbound.data.line,
381                                       linelen);
382           putc ('\n', ctx->log_fp);
383             }
384       *line++ = '\n';
385       linelen++;
386       if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
387         {
388           ctx->outbound.data.error = ASSUAN_Write_Error;
389           return 0;
390         }
391       ctx->outbound.data.linelen = 0;
392     }
393   return 0;
394 }
395
396
397 /**
398  * assuan_send_data:
399  * @ctx: An assuan context
400  * @buffer: Data to send or NULL to flush
401  * @length: length of the data to send/
402  * 
403  * This function may be used by the server or the client to send data
404  * lines.  The data will be escaped as required by the Assuan protocol
405  * and may get buffered until a line is full.  To force sending the
406  * data out @buffer may be passed as NULL (in which case @length must
407  * also be 0); however when used by a client this flush operation does
408  * also send the terminating "END" command to terminate the reponse on
409  * a INQUIRE response.  However, when assuan_transact() is used, this
410  * function takes care of sending END itself.
411  * 
412  * Return value: 0 on success or an error code
413  **/
414 \f
415 AssuanError
416 assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
417 {
418   if (!ctx)
419     return ASSUAN_Invalid_Value;
420   if (!buffer && length)
421     return ASSUAN_Invalid_Value;
422
423   if (!buffer)
424     { /* flush what we have */
425       _assuan_cookie_write_flush (ctx);
426       if (ctx->outbound.data.error)
427         return ctx->outbound.data.error;
428       if (!ctx->is_server)
429         return assuan_write_line (ctx, "END");
430     }
431   else
432     {
433       _assuan_cookie_write_data (ctx, buffer, length);
434       if (ctx->outbound.data.error)
435         return ctx->outbound.data.error;
436     }
437
438   return 0;
439 }
440
441
442
443