LCOV - code coverage report
Current view: top level - src - client.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 84 149 56.4 %
Date: 2015-11-05 17:06:03 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* client.c - Functions common to all clients.
       2             :    Copyright (C) 2009 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, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdlib.h>
      26             : 
      27             : #include "assuan-defs.h"
      28             : #include "debug.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             : void
      36           2 : _assuan_client_finish (assuan_context_t ctx)
      37             : {
      38           2 :   if (ctx->inbound.fd != ASSUAN_INVALID_FD)
      39             :     {
      40           2 :       _assuan_close (ctx, ctx->inbound.fd);
      41           2 :       if (ctx->inbound.fd == ctx->outbound.fd)
      42           1 :         ctx->outbound.fd = ASSUAN_INVALID_FD;
      43           2 :       ctx->inbound.fd = ASSUAN_INVALID_FD;
      44             :     }
      45           2 :   if (ctx->outbound.fd != ASSUAN_INVALID_FD)
      46             :     {
      47           1 :       _assuan_close (ctx, ctx->outbound.fd);
      48           1 :       ctx->outbound.fd = ASSUAN_INVALID_FD;
      49             :     }
      50           2 :   if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid)
      51             :     {
      52           1 :       _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
      53           1 :       ctx->pid = ASSUAN_INVALID_PID;
      54             :     }
      55             : 
      56           2 :   _assuan_uds_deinit (ctx);
      57           2 : }
      58             : 
      59             : 
      60             : /* Disconnect and release the context CTX.  */
      61             : void
      62           2 : _assuan_client_release (assuan_context_t ctx)
      63             : {
      64           2 :   assuan_write_line (ctx, "BYE");
      65             : 
      66           2 :   _assuan_client_finish (ctx);
      67           2 : }
      68             : 
      69             : 
      70             : /* This function also does deescaping for data lines.  */
      71             : gpg_error_t
      72          17 : assuan_client_read_response (assuan_context_t ctx,
      73             :                              char **line_r, int *linelen_r)
      74             : {
      75             :   gpg_error_t rc;
      76          17 :   char *line = NULL;
      77          17 :   int linelen = 0;
      78             : 
      79          17 :   *line_r = NULL;
      80          17 :   *linelen_r = 0;
      81             : 
      82             :   do
      83             :     {
      84             :       do
      85             :         {
      86          17 :           rc = _assuan_read_line (ctx);
      87             :         }
      88          17 :       while (_assuan_error_is_eagain (ctx, rc));
      89          17 :       if (rc)
      90           0 :         return rc;
      91          17 :       line = ctx->inbound.line;
      92          17 :       linelen = ctx->inbound.linelen;
      93             :     }
      94          17 :   while (!linelen);
      95             : 
      96             :   /* For data lines, we deescape immediately.  The user will never
      97             :      have to worry about it.  */
      98          17 :   if (linelen >= 1 && line[0] == 'D' && line[1] == ' ')
      99             :     {
     100             :       char *s, *d;
     101          67 :       for (s=d=line; linelen; linelen--)
     102             :         {
     103          66 :           if (*s == '%' && linelen > 2)
     104             :             { /* handle escaping */
     105           0 :               s++;
     106           0 :               *d++ = xtoi_2 (s);
     107           0 :               s += 2;
     108           0 :               linelen -= 2;
     109             :             }
     110             :           else
     111          66 :             *d++ = *s++;
     112             :         }
     113           1 :       *d = 0; /* add a hidden string terminator */
     114             : 
     115           1 :       linelen = d - line;
     116           1 :       ctx->inbound.linelen = linelen;
     117             :     }
     118             : 
     119          17 :   *line_r = line;
     120          17 :   *linelen_r = linelen;
     121             : 
     122          17 :   return 0;
     123             : }
     124             : 
     125             : 
     126             : gpg_error_t
     127          17 : assuan_client_parse_response (assuan_context_t ctx, char *line, int linelen,
     128             :                               assuan_response_t *response, int *off)
     129             : {
     130          17 :   *response = ASSUAN_RESPONSE_ERROR;
     131          17 :   *off = 0;
     132             : 
     133          17 :   if (linelen >= 1
     134          17 :       && line[0] == 'D' && line[1] == ' ')
     135             :     {
     136           1 :       *response = ASSUAN_RESPONSE_DATA; /* data line */
     137           1 :       *off = 2;
     138             :     }
     139          16 :   else if (linelen >= 1
     140          16 :            && line[0] == 'S'
     141           0 :            && (line[1] == '\0' || line[1] == ' '))
     142             :     {
     143           0 :       *response = ASSUAN_RESPONSE_STATUS;
     144           0 :       *off = 1;
     145           0 :       while (line[*off] == ' ')
     146           0 :         ++*off;
     147             :     }
     148          32 :   else if (linelen >= 2
     149          16 :            && line[0] == 'O' && line[1] == 'K'
     150          16 :            && (line[2] == '\0' || line[2] == ' '))
     151             :     {
     152          16 :       *response = ASSUAN_RESPONSE_OK;
     153          16 :       *off = 2;
     154          35 :       while (line[*off] == ' ')
     155           3 :         ++*off;
     156             :     }
     157           0 :   else if (linelen >= 3
     158           0 :            && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
     159           0 :            && (line[3] == '\0' || line[3] == ' '))
     160             :     {
     161           0 :       *response = ASSUAN_RESPONSE_ERROR;
     162           0 :       *off = 3;
     163           0 :       while (line[*off] == ' ')
     164           0 :         ++*off;
     165             :     }
     166           0 :   else if (linelen >= 7
     167           0 :            && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
     168           0 :            && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
     169           0 :            && line[6] == 'E'
     170           0 :            && (line[7] == '\0' || line[7] == ' '))
     171             :     {
     172           0 :       *response = ASSUAN_RESPONSE_INQUIRE;
     173           0 :       *off = 7;
     174           0 :       while (line[*off] == ' ')
     175           0 :         ++*off;
     176             :     }
     177           0 :   else if (linelen >= 3
     178           0 :            && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
     179           0 :            && (line[3] == '\0' || line[3] == ' '))
     180             :     {
     181           0 :       *response = ASSUAN_RESPONSE_END;
     182           0 :       *off = 3;
     183             :     }
     184           0 :   else if (linelen >= 1 && line[0] == '#')
     185             :     {
     186           0 :       *response = ASSUAN_RESPONSE_COMMENT;
     187           0 :       *off = 1;
     188             :     }
     189             :   else
     190           0 :     return _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE);
     191             : 
     192          17 :   return 0;
     193             : }
     194             : 
     195             : 
     196             : gpg_error_t
     197          17 : _assuan_read_from_server (assuan_context_t ctx, assuan_response_t *response,
     198             :                           int *off, int convey_comments)
     199             : {
     200             :   gpg_error_t rc;
     201             :   char *line;
     202             :   int linelen;
     203             : 
     204             :   do
     205             :     {
     206          17 :       *response = ASSUAN_RESPONSE_ERROR;
     207          17 :       *off = 0;
     208          17 :       rc = assuan_client_read_response (ctx, &line, &linelen);
     209          17 :       if (!rc)
     210          17 :         rc = assuan_client_parse_response (ctx, line, linelen, response, off);
     211             :     }
     212          17 :   while (!rc && *response == ASSUAN_RESPONSE_COMMENT && !convey_comments);
     213             : 
     214          17 :   return rc;
     215             : }
     216             : 
     217             : 
     218             : /**
     219             :  * assuan_transact:
     220             :  * @ctx: The Assuan context
     221             :  * @command: Command line to be send to the server
     222             :  * @data_cb: Callback function for data lines
     223             :  * @data_cb_arg: first argument passed to @data_cb
     224             :  * @inquire_cb: Callback function for a inquire response
     225             :  * @inquire_cb_arg: first argument passed to @inquire_cb
     226             :  * @status_cb: Callback function for a status response
     227             :  * @status_cb_arg: first argument passed to @status_cb
     228             :  *
     229             :  * FIXME: Write documentation
     230             :  *
     231             :  * Return value: 0 on success or an error code.  The error code may be
     232             :  * the one one returned by the server via error lines or from the
     233             :  * callback functions.  Take care:  If a callback returns an error
     234             :  * this function returns immediately with this error.
     235             :  **/
     236             : gpg_error_t
     237          14 : assuan_transact (assuan_context_t ctx,
     238             :                  const char *command,
     239             :                  gpg_error_t (*data_cb)(void *, const void *, size_t),
     240             :                  void *data_cb_arg,
     241             :                  gpg_error_t (*inquire_cb)(void*, const char *),
     242             :                  void *inquire_cb_arg,
     243             :                  gpg_error_t (*status_cb)(void*, const char *),
     244             :                  void *status_cb_arg)
     245             : {
     246             :   gpg_error_t rc;
     247             :   assuan_response_t response;
     248             :   int off;
     249             :   char *line;
     250             :   int linelen;
     251             : 
     252          14 :   rc = assuan_write_line (ctx, command);
     253          14 :   if (rc)
     254           0 :     return rc;
     255             : 
     256          14 :   if (*command == '#' || !*command)
     257           0 :     return 0; /* Don't expect a response for a comment line.  */
     258             : 
     259             :  again:
     260          15 :   rc = _assuan_read_from_server (ctx, &response, &off,
     261          15 :                                  ctx->flags.convey_comments);
     262          15 :   if (rc)
     263           0 :     return rc; /* error reading from server */
     264             : 
     265          15 :   line = ctx->inbound.line + off;
     266          15 :   linelen = ctx->inbound.linelen - off;
     267             : 
     268          15 :   if (response == ASSUAN_RESPONSE_ERROR)
     269           0 :     rc = atoi (line);
     270          15 :   else if (response == ASSUAN_RESPONSE_DATA)
     271             :     {
     272           1 :       if (!data_cb)
     273           0 :         rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
     274             :       else
     275             :         {
     276           1 :           rc = data_cb (data_cb_arg, line, linelen);
     277           1 :           if (!rc)
     278           1 :             goto again;
     279             :         }
     280             :     }
     281          14 :   else if (response == ASSUAN_RESPONSE_INQUIRE)
     282             :     {
     283           0 :       if (!inquire_cb)
     284             :         {
     285           0 :           assuan_write_line (ctx, "END"); /* get out of inquire mode */
     286           0 :           _assuan_read_from_server (ctx, &response, &off, 0); /* dummy read */
     287           0 :           rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB);
     288             :         }
     289             :       else
     290             :         {
     291           0 :           rc = inquire_cb (inquire_cb_arg, line);
     292           0 :           if (!rc)
     293           0 :             rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
     294             :           else
     295             :             { /* Flush and send CAN.  */
     296             :               /* Note that in this error case we don't want to return
     297             :                  an error code from sending the cancel.  The dummy
     298             :                  read is to remove the response from the server which
     299             :                  we are not interested in.  */
     300           0 :               assuan_send_data (ctx, NULL, 1);
     301           0 :               _assuan_read_from_server (ctx, &response, &off, 0);
     302             :             }
     303           0 :           if (!rc)
     304           0 :             goto again;
     305             :         }
     306             :     }
     307          14 :   else if (response == ASSUAN_RESPONSE_STATUS)
     308             :     {
     309           0 :       if (status_cb)
     310           0 :         rc = status_cb (status_cb_arg, line);
     311           0 :       if (!rc)
     312           0 :         goto again;
     313             :     }
     314          14 :   else if (response == ASSUAN_RESPONSE_COMMENT && ctx->flags.convey_comments)
     315             :     {
     316           0 :       line -= off; /* Send line with the comment marker.  */
     317           0 :       if (status_cb)
     318           0 :         rc = status_cb (status_cb_arg, line);
     319           0 :       if (!rc)
     320           0 :         goto again;
     321             :     }
     322          14 :   else if (response == ASSUAN_RESPONSE_END)
     323             :     {
     324           0 :       if (!data_cb)
     325           0 :         rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
     326             :       else
     327             :         {
     328           0 :           rc = data_cb (data_cb_arg, NULL, 0);
     329           0 :           if (!rc)
     330           0 :             goto again;
     331             :         }
     332             :     }
     333             : 
     334          14 :   return rc;
     335             : }

Generated by: LCOV version 1.11