Update to rev 231 of libassuan.
[gpgme.git] / assuan / assuan-buffer.c
1 /* assuan-buffer.c - read and send data
2  * Copyright (C) 2001, 2002, 2003, 2004, 2006 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 <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #ifdef HAVE_W32_SYSTEM
30 #include <process.h>
31 #endif
32 #include "assuan-defs.h"
33
34
35 /* Extended version of write(2) to guarantee that all bytes are
36    written.  Returns 0 on success or -1 and ERRNO on failure. */
37 static int
38 writen (assuan_context_t ctx, const char *buffer, size_t length)
39 {
40   while (length)
41     {
42       ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
43       
44       if (nwritten < 0)
45         {
46           if (errno == EINTR)
47             continue;
48           return -1; /* write error */
49         }
50       length -= nwritten;
51       buffer += nwritten;
52     }
53   return 0;  /* okay */
54 }
55
56 /* Read an entire line. Returns 0 on success or -1 and ERRNo on
57    failure.  EOF is indictated by setting the integer at address
58    R_EOF.  */
59 static int
60 readline (assuan_context_t ctx, char *buf, size_t buflen,
61           int *r_nread, int *r_eof)
62 {
63   size_t nleft = buflen;
64   char *p;
65
66   *r_eof = 0;
67   *r_nread = 0;
68   while (nleft > 0)
69     {
70       ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
71
72       if (n < 0)
73         {
74           if (errno == EINTR)
75             continue;
76           return -1; /* read error */
77         }
78       else if (!n)
79         {
80           *r_eof = 1;
81           break; /* allow incomplete lines */
82         }
83       p = buf;
84       nleft -= n;
85       buf += n;
86       *r_nread += n;
87
88       p = memrchr (p, '\n', n);
89       if (p)
90         break; /* at least one full line available - that's enough for now */
91     }
92
93   return 0;
94 }
95
96
97 /* Function returns an Assuan error. */
98 assuan_error_t
99 _assuan_read_line (assuan_context_t ctx)
100 {
101   char *line = ctx->inbound.line;
102   int nread, atticlen;
103   int rc;
104   char *endp = 0;
105
106   if (ctx->inbound.eof)
107     return _assuan_error (-1);
108
109   atticlen = ctx->inbound.attic.linelen;
110   if (atticlen)
111     {
112       memcpy (line, ctx->inbound.attic.line, atticlen);
113       ctx->inbound.attic.linelen = 0;
114
115       endp = memchr (line, '\n', atticlen);
116       if (endp)
117         /* Found another line in the attic.  */
118         {
119           rc = 0;
120           nread = atticlen;
121           atticlen = 0;
122         }
123       else
124         /* There is pending data but not a full line.  */
125         {
126           assert (atticlen < LINELENGTH);
127           rc = readline (ctx, line + atticlen,
128                          LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
129         }
130     }
131   else
132     /* No pending data.  */
133     rc = readline (ctx, line, LINELENGTH,
134                    &nread, &ctx->inbound.eof);
135   if (rc)
136     {
137       if (ctx->log_fp)
138         fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n",
139                  assuan_get_assuan_log_prefix (),
140                  (unsigned int)getpid (), ctx->inbound.fd,
141                  strerror (errno));
142       return _assuan_error (ASSUAN_Read_Error);
143     }
144   if (!nread)
145     {
146       assert (ctx->inbound.eof);
147       if (ctx->log_fp)
148         fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n",
149                  assuan_get_assuan_log_prefix (),
150                  (unsigned int)getpid (), ctx->inbound.fd);
151       return _assuan_error (-1);
152     }
153
154   ctx->inbound.attic.pending = 0;
155   nread += atticlen;
156
157   if (! endp)
158     endp = memchr (line, '\n', nread);
159
160   if (endp)
161     {
162       unsigned monitor_result;
163       int n = endp - line + 1;
164
165       if (n < nread)
166         /* LINE contains more than one line.  We copy it to the attic
167            now as handlers are allowed to modify the passed
168            buffer.  */
169         {
170           int len = nread - n;
171           memcpy (ctx->inbound.attic.line, endp + 1, len);
172           ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
173           ctx->inbound.attic.linelen = len;
174         }
175
176       if (endp != line && endp[-1] == '\r')
177         endp --;
178       *endp = 0;
179
180       ctx->inbound.linelen = endp - line;
181
182       monitor_result = (ctx->io_monitor
183                         ? ctx->io_monitor (ctx, 0,
184                                            ctx->inbound.line,
185                                            ctx->inbound.linelen)
186                         : 0);
187       if ( (monitor_result & 2) )
188         ctx->inbound.linelen = 0;
189       
190       if (ctx->log_fp && !(monitor_result & 1))
191         {
192           fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ",
193                    assuan_get_assuan_log_prefix (),
194                    (unsigned int)getpid (), ctx->inbound.fd);
195           if (ctx->confidential)
196             fputs ("[Confidential data not shown]", ctx->log_fp);
197           else
198             _assuan_log_print_buffer (ctx->log_fp,
199                                       ctx->inbound.line,
200                                       ctx->inbound.linelen);
201           putc ('\n', ctx->log_fp);
202         }
203       return 0;
204     }
205   else
206     {
207       if (ctx->log_fp)
208         fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n",
209                  assuan_get_assuan_log_prefix (),
210                  (unsigned int)getpid (), ctx->inbound.fd);
211       *line = 0;
212       ctx->inbound.linelen = 0;
213       return _assuan_error (ctx->inbound.eof 
214                             ? ASSUAN_Line_Not_Terminated
215                             : ASSUAN_Line_Too_Long);
216     }
217 }
218
219
220 /* Read the next line from the client or server and return a pointer
221    in *LINE to a buffer holding the line.  LINELEN is the length of
222    *LINE.  The buffer is valid until the next read operation on it.
223    The caller may modify the buffer.  The buffer is invalid (i.e. must
224    not be used) if an error is returned.
225
226    Returns 0 on success or an assuan error code.
227    See also: assuan_pending_line().
228 */
229 assuan_error_t
230 assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
231 {
232   assuan_error_t err;
233
234   if (!ctx)
235     return _assuan_error (ASSUAN_Invalid_Value);
236
237   err = _assuan_read_line (ctx);
238   *line = ctx->inbound.line;
239   *linelen = ctx->inbound.linelen;
240   return err;
241 }
242
243
244 /* Return true if a full line is buffered (i.e. an entire line may be
245    read without any I/O).  */
246 int
247 assuan_pending_line (assuan_context_t ctx)
248 {
249   return ctx && ctx->inbound.attic.pending;
250 }
251
252
253 assuan_error_t 
254 _assuan_write_line (assuan_context_t ctx, const char *prefix,
255                     const char *line, size_t len)
256 {
257   assuan_error_t rc = 0;
258   size_t prefixlen = prefix? strlen (prefix):0;
259   unsigned int monitor_result;
260
261   /* Make sure that the line is short enough. */
262   if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
263     {
264       if (ctx->log_fp)
265         fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
266                  "[supplied line too long -truncated]\n",
267                  assuan_get_assuan_log_prefix (),
268                  (unsigned int)getpid (), ctx->inbound.fd);
269       if (prefixlen > 5)
270         prefixlen = 5;
271       if (len > ASSUAN_LINELENGTH - prefixlen - 2)
272         len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
273     }
274
275   monitor_result = (ctx->io_monitor
276                     ? ctx->io_monitor (ctx, 1, line, len)
277                     : 0);
278
279   /* Fixme: we should do some kind of line buffering.  */
280   if (ctx->log_fp && !(monitor_result & 1))
281     {
282       fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
283                assuan_get_assuan_log_prefix (),
284                (unsigned int)getpid (), ctx->inbound.fd);
285       if (ctx->confidential)
286         fputs ("[Confidential data not shown]", ctx->log_fp);
287       else
288         {
289           if (prefixlen)
290             _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen);
291           _assuan_log_print_buffer (ctx->log_fp, line, len);
292         }
293       putc ('\n', ctx->log_fp);
294     }
295
296   if (prefixlen && !(monitor_result & 2))
297     {
298       rc = writen (ctx, prefix, prefixlen);
299       if (rc)
300         rc = _assuan_error (ASSUAN_Write_Error);
301     }
302   if (!rc && !(monitor_result & 2))
303     {
304       rc = writen (ctx, line, len);
305       if (rc)
306         rc = _assuan_error (ASSUAN_Write_Error);
307       if (!rc)
308         {
309           rc = writen (ctx, "\n", 1);
310           if (rc)
311             rc = _assuan_error (ASSUAN_Write_Error);
312         }
313     }
314   return rc;
315 }
316
317
318 assuan_error_t 
319 assuan_write_line (assuan_context_t ctx, const char *line)
320 {
321   size_t len;
322   const char *s;
323
324   if (!ctx)
325     return _assuan_error (ASSUAN_Invalid_Value);
326
327   /* Make sure that we never take a LF from the user - this might
328      violate the protocol. */
329   s = strchr (line, '\n');
330   len = s? (s-line) : strlen (line);
331
332   if (ctx->log_fp && s)
333     fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
334              "[supplied line contained a LF - truncated]\n",
335              assuan_get_assuan_log_prefix (),
336              (unsigned int)getpid (), ctx->inbound.fd);
337
338   return _assuan_write_line (ctx, NULL, line, len);
339 }
340
341
342 \f
343 /* Write out the data in buffer as datalines with line wrapping and
344    percent escaping.  This function is used for GNU's custom streams. */
345 int
346 _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
347 {
348   assuan_context_t ctx = cookie;
349   size_t size = orig_size;
350   char *line;
351   size_t linelen;
352
353   if (ctx->outbound.data.error)
354     return 0;
355
356   line = ctx->outbound.data.line;
357   linelen = ctx->outbound.data.linelen;
358   line += linelen;
359   while (size)
360     {
361       unsigned int monitor_result;
362
363       /* Insert data line header. */
364       if (!linelen)
365         {
366           *line++ = 'D';
367           *line++ = ' ';
368           linelen += 2;
369         }
370       
371       /* Copy data, keep space for the CRLF and to escape one character. */
372       while (size && linelen < LINELENGTH-2-2)
373         {
374           if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
375             {
376               sprintf (line, "%%%02X", *(unsigned char*)buffer);
377               line += 3;
378               linelen += 3;
379               buffer++;
380             }
381           else
382             {
383               *line++ = *buffer++;
384               linelen++;
385             }
386           size--;
387         }
388       
389       
390       monitor_result = (ctx->io_monitor
391                         ? ctx->io_monitor (ctx, 1,
392                                            ctx->outbound.data.line, linelen)
393                         : 0);
394
395       if (linelen >= LINELENGTH-2-2)
396         {
397           if (ctx->log_fp && !(monitor_result & 1))
398             {
399               fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
400                        assuan_get_assuan_log_prefix (),
401                        (unsigned int)getpid (), ctx->inbound.fd);
402
403               if (ctx->confidential)
404                 fputs ("[Confidential data not shown]", ctx->log_fp);
405               else 
406                 _assuan_log_print_buffer (ctx->log_fp, 
407                                           ctx->outbound.data.line,
408                                           linelen);
409               putc ('\n', ctx->log_fp);
410             }
411           *line++ = '\n';
412           linelen++;
413           if ( !(monitor_result & 2)
414                && writen (ctx, ctx->outbound.data.line, linelen))
415             {
416               ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
417               return 0;
418             }
419           line = ctx->outbound.data.line;
420           linelen = 0;
421         }
422     }
423
424   ctx->outbound.data.linelen = linelen;
425   return (int)orig_size;
426 }
427
428
429 /* Write out any buffered data 
430    This function is used for GNU's custom streams */
431 int
432 _assuan_cookie_write_flush (void *cookie)
433 {
434   assuan_context_t ctx = cookie;
435   char *line;
436   size_t linelen;
437   unsigned int monitor_result;
438
439   if (ctx->outbound.data.error)
440     return 0;
441
442   line = ctx->outbound.data.line;
443   linelen = ctx->outbound.data.linelen;
444   line += linelen;
445
446   monitor_result = (ctx->io_monitor
447                     ? ctx->io_monitor (ctx, 1,
448                                        ctx->outbound.data.line, linelen)
449                     : 0);
450   
451   if (linelen)
452     {
453       if (ctx->log_fp && !(monitor_result & 1))
454         {
455           fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
456                    assuan_get_assuan_log_prefix (),
457                    (unsigned int)getpid (), ctx->inbound.fd);
458           if (ctx->confidential)
459             fputs ("[Confidential data not shown]", ctx->log_fp);
460           else
461             _assuan_log_print_buffer (ctx->log_fp,
462                                       ctx->outbound.data.line, linelen);
463           putc ('\n', ctx->log_fp);
464         }
465       *line++ = '\n';
466       linelen++;
467       if ( !(monitor_result & 2)
468            && writen (ctx, ctx->outbound.data.line, linelen))
469         {
470           ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
471           return 0;
472         }
473       ctx->outbound.data.linelen = 0;
474     }
475   return 0;
476 }
477
478
479 /**
480  * assuan_send_data:
481  * @ctx: An assuan context
482  * @buffer: Data to send or NULL to flush
483  * @length: length of the data to send/
484  * 
485  * This function may be used by the server or the client to send data
486  * lines.  The data will be escaped as required by the Assuan protocol
487  * and may get buffered until a line is full.  To force sending the
488  * data out @buffer may be passed as NULL (in which case @length must
489  * also be 0); however when used by a client this flush operation does
490  * also send the terminating "END" command to terminate the reponse on
491  * a INQUIRE response.  However, when assuan_transact() is used, this
492  * function takes care of sending END itself.
493  * 
494  * Return value: 0 on success or an error code
495  **/
496 \f
497 assuan_error_t
498 assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
499 {
500   if (!ctx)
501     return _assuan_error (ASSUAN_Invalid_Value);
502   if (!buffer && length)
503     return _assuan_error (ASSUAN_Invalid_Value);
504
505   if (!buffer)
506     { /* flush what we have */
507       _assuan_cookie_write_flush (ctx);
508       if (ctx->outbound.data.error)
509         return ctx->outbound.data.error;
510       if (!ctx->is_server)
511         return assuan_write_line (ctx, "END");
512     }
513   else
514     {
515       _assuan_cookie_write_data (ctx, buffer, length);
516       if (ctx->outbound.data.error)
517         return ctx->outbound.data.error;
518     }
519
520   return 0;
521 }
522
523 assuan_error_t
524 assuan_sendfd (assuan_context_t ctx, int fd)
525 {
526   /* It is explicitly allowed to use (NULL, -1) as a runtime test to
527      check whether descriptor passing is available. */
528   if (!ctx && fd == -1)
529 #ifdef USE_DESCRIPTOR_PASSING
530     return 0;
531 #else
532     return _assuan_error (ASSUAN_Not_Implemented);
533 #endif
534
535   if (! ctx->io->sendfd)
536     return set_error (ctx, Not_Implemented,
537                       "server does not support sending and receiving "
538                       "of file descriptors");
539   return ctx->io->sendfd (ctx, fd);
540 }
541
542 assuan_error_t
543 assuan_receivefd (assuan_context_t ctx, int *fd)
544 {
545   if (! ctx->io->receivefd)
546     return set_error (ctx, Not_Implemented,
547                       "server does not support sending and receiving "
548                       "of file descriptors");
549   return ctx->io->receivefd (ctx, fd);
550 }