Enhanced gpg-conect-agent scripting.
[gnupg.git] / tools / gpg-connect-agent.c
1 /* gpg-connect-agent.c - Tool to connect to the agent.
2  *      Copyright (C) 2005, 2007 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <assuan.h>
28 #include <unistd.h>
29
30 #include "i18n.h"
31 #include "../common/util.h"
32 #include "../common/asshelp.h"
33 #include "../common/sysutils.h"
34 #include "../common/membuf.h"
35 #include "../common/ttyio.h"
36
37 #define CONTROL_D ('D' - 'A' + 1)
38 #define octdigitp(p) (*(p) >= '0' && *(p) <= '7')
39
40 /* Constants to identify the commands and options. */
41 enum cmd_and_opt_values
42   {
43     aNull = 0,
44     oQuiet      = 'q',
45     oVerbose    = 'v',
46     oRawSocket  = 'S',
47     oExec       = 'E',
48     oRun        = 'r',
49     oSubst      = 's',
50
51     oNoVerbose  = 500,
52     oHomedir,
53     oHex,
54     oDecode,
55     oNoExtConnect
56
57   };
58
59
60 /* The list of commands and options. */
61 static ARGPARSE_OPTS opts[] =
62   {
63     { 301, NULL, 0, N_("@\nOptions:\n ") },
64     
65     { oVerbose, "verbose",  0, N_("verbose") },
66     { oQuiet, "quiet",      0, N_("quiet") },
67     { oHex,   "hex",        0, N_("print data out hex encoded") },
68     { oDecode,"decode",     0, N_("decode received data lines") },
69     { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
70     { oExec, "exec", 0, N_("run the Assuan server given on the command line")},
71     { oNoExtConnect, "no-ext-connect",
72                             0, N_("do not use extended connect mode")},
73     { oRun,  "run", 2,         N_("|FILE|run commands from FILE on startup")},
74     { oSubst, "subst", 0,      N_("run /subst on startup")}, 
75     /* hidden options */
76     { oNoVerbose, "no-verbose",  0, "@"},
77     { oHomedir, "homedir", 2, "@" },   
78     {0}
79   };
80
81
82 /* We keep all global options in the structure OPT.  */
83 struct
84 {
85   int verbose;          /* Verbosity level.  */
86   int quiet;            /* Be extra quiet.  */
87   const char *homedir;  /* Configuration directory name */
88   int hex;              /* Print data lines in hex format. */
89   int decode;           /* Decode received data lines.  */
90   const char *raw_socket; /* Name of socket to connect in raw mode. */
91   int exec;             /* Run the pgm given on the command line. */
92   unsigned int connect_flags;    /* Flags used for connecting. */
93   int enable_varsubst;  /* Set if variable substitution is enabled.  */
94 } opt;
95
96
97
98 /* Definitions for /definq commands and a global linked list with all
99    the definitions. */
100 struct definq_s
101 {
102   struct definq_s *next;
103   char *name;     /* Name of inquiry or NULL for any name. */
104   int is_var;     /* True if FILE is a variable name. */
105   int is_prog;    /* True if FILE is a program to run. */
106   char file[1];   /* Name of file or program. */
107 };
108 typedef struct definq_s *definq_t;
109
110 static definq_t definq_list;
111 static definq_t *definq_list_tail = &definq_list;
112
113
114 /* Variable definitions and glovbal table.  */
115 struct variable_s
116 {
117   struct variable_s *next;
118   char *value;  /* Malloced value - always a string.  */
119   char name[1]; /* Name of the variable.  */
120 };
121 typedef struct variable_s *variable_t;
122
123 static variable_t variable_table;
124
125 /* This is used to store the pid of the server.  */
126 static pid_t server_pid = (pid_t)(-1);
127
128
129 /* A list of open file descriptors. */
130 static struct
131 {
132   int inuse;
133 #ifdef HAVE_W32_SYSTEM
134   HANDLE handle;
135 #endif
136 } open_fd_table[256];
137
138
139 /*-- local prototypes --*/
140 static char *substitute_line_copy (const char *buffer);
141 static int read_and_print_response (assuan_context_t ctx, int *r_goterr);
142 static assuan_context_t start_agent (void);
143
144
145
146 \f
147 /* Print usage information and and provide strings for help. */
148 static const char *
149 my_strusage( int level )
150 {
151   const char *p;
152
153   switch (level)
154     {
155     case 11: p = "gpg-connect-agent (GnuPG)";
156       break;
157     case 13: p = VERSION; break;
158     case 17: p = PRINTABLE_OS_NAME; break;
159     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
160       break;
161     case 1:
162     case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)");
163       break;
164     case 41:
165       p = _("Syntax: gpg-connect-agent [options]\n"
166             "Connect to a running agent and send commands\n");
167       break;
168     case 31: p = "\nHome: "; break;
169     case 32: p = opt.homedir; break;
170     case 33: p = "\n"; break;
171
172     default: p = NULL; break;
173     }
174   return p;
175 }
176
177
178 static char *
179 gnu_getcwd (void)
180 {
181   char *buffer;
182   size_t size = 100;
183
184   for (;;)
185     {
186       buffer = xmalloc (size+1);
187       if (getcwd (buffer, size) == buffer)
188         return buffer;
189       xfree (buffer);
190       if (errno != ERANGE)
191         return NULL;
192       size *= 2;
193     }
194 }
195
196
197 /* Unescale STRING and returned the malloced result.  The surrounding
198    quotes must already be removed from STRING.  */
199 static char *
200 unescape_string (const char *string)
201 {
202   const unsigned char *s;
203   int esc;
204   size_t n;
205   char *buffer;
206   unsigned char *d;
207
208   n = 0;
209   for (s = (const unsigned char*)string, esc=0; *s; s++)
210     {
211       if (esc)
212         {
213           switch (*s)
214             {
215             case 'b':  
216             case 't':  
217             case 'v':  
218             case 'n':  
219             case 'f':  
220             case 'r':  
221             case '"':  
222             case '\'': 
223             case '\\': n++; break;
224             case 'x': 
225               if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
226                 n++;
227               break;
228
229             default:
230               if (s[1] && s[2] 
231                   && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
232                 n++;
233               break;
234             }
235           esc = 0;
236         }
237       else if (*s == '\\')
238         esc = 1;
239       else
240         n++;
241     } 
242
243   buffer = xmalloc (n+1);
244   d = (unsigned char*)buffer;
245   for (s = (const unsigned char*)string, esc=0; *s; s++)
246     {
247       if (esc)
248         {
249           switch (*s)
250             {
251             case 'b':  *d++ = '\b'; break;
252             case 't':  *d++ = '\t'; break;
253             case 'v':  *d++ = '\v'; break;
254             case 'n':  *d++ = '\n'; break;
255             case 'f':  *d++ = '\f'; break;
256             case 'r':  *d++ = '\r'; break;
257             case '"':  *d++ = '\"'; break;
258             case '\'': *d++ = '\''; break;
259             case '\\': *d++ = '\\'; break;
260             case 'x': 
261               if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
262                 {
263                   s++;
264                   *d++ = xtoi_2 (s);
265                   s++;
266                 }
267               break;
268
269             default:
270               if (s[1] && s[2] 
271                   && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
272                 {
273                   *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
274                   s += 2;
275                 }
276               break;
277             }
278           esc = 0;
279         }
280       else if (*s == '\\')
281         esc = 1;
282       else
283         *d++ = *s;
284     } 
285   *d = 0;
286   return buffer;
287 }
288
289
290 /* Do the percent unescaping and return a newly malloced string.
291    If WITH_PLUS is set '+' characters will be changed to space. */
292 static char *
293 unpercent_string (const char *string, int with_plus)
294 {
295   const unsigned char *s;
296   unsigned char *buffer, *p;
297   size_t n;
298
299   n = 0;
300   for (s=(const unsigned char *)string; *s; s++)
301     {
302       if (*s == '%' && s[1] && s[2])
303         { 
304           s++;
305           n++;
306           s++;
307         }
308       else if (with_plus && *s == '+')
309         n++;
310       else
311         n++;
312     }
313
314   buffer = xmalloc (n+1);
315   p = buffer;
316   for (s=(const unsigned char *)string; *s; s++)
317     {
318       if (*s == '%' && s[1] && s[2])
319         { 
320           s++;
321           *p++ = xtoi_2 (s);
322           s++;
323         }
324       else if (with_plus && *s == '+')
325         *p++ = ' ';
326       else
327         *p++ = *s;
328     }
329   *p = 0;
330   return (char*)buffer;
331 }
332
333
334
335
336 \f
337 static const char *
338 set_var (const char *name, const char *value)
339 {
340   variable_t var;
341
342   for (var = variable_table; var; var = var->next)
343     if (!strcmp (var->name, name))
344       break;
345   if (!var)
346     {
347       var = xmalloc (sizeof *var + strlen (name));
348       var->value = NULL;
349       strcpy (var->name, name);
350       var->next = variable_table;
351       variable_table = var;
352     }
353   xfree (var->value);
354   var->value = value? xstrdup (value) : NULL;
355   return var->value;
356 }    
357
358
359 static void
360 set_int_var (const char *name, int value)
361 {
362   char numbuf[35];
363
364   snprintf (numbuf, sizeof numbuf, "%d", value);
365   set_var (name, numbuf);
366 }
367
368
369 /* Return the value of a variable.  That value is valid until a
370    variable of the name is changed.  Return NULL if not found.  Note
371    that envvars are copied to our variable list at the first access
372    and not at oprogram start.  */
373 static const char *
374 get_var (const char *name)
375 {
376   variable_t var;
377   const char *s;
378
379   if (!*name)
380     return "";
381   for (var = variable_table; var; var = var->next)
382     if (!strcmp (var->name, name))
383       break;
384   if (!var && (s = getenv (name)))
385     return set_var (name, s);
386   if (!var || !var->value)
387     return NULL;
388   return var->value;
389 }
390
391
392 /* Extended version of get_var.  This returns a malloced string and
393    understand the fucntion syntax: "func args". 
394
395    Defined functions are
396    
397      get - Return a value described by the next argument:
398            cwd        - The current working directory.
399            homedir    - The gnupg homedir.
400            sysconfdir - GnuPG's system configuration directory.
401            bindir     - GnuPG's binary directory.
402            libdir     - GnuPG's library directory.
403            libexecdir - GnuPG's library directory for executable files.
404            datadir    - GnuPG's data directory.
405            serverpid  - The PID of the current server.
406
407      unescape ARGS
408            Remove C-style escapes from string.  Note that "\0" and
409            "\x00" terminate the string implictly.  Use "\x7d" to
410            represent the closing brace.  The args start right after
411            the first space after the function name.
412
413      unpercent ARGS
414      unpercent+ ARGS
415            Remove percent style ecaping from string.  NOte that "%00
416            terminates the string implicitly.  Use "%7d" to represetn
417            the closing brace.  The args start right after the first
418            space after the function name.  "unpercent+" also maps '+'
419            to space.
420
421      percent ARGS
422      percent+ ARGS
423            Escape the args using the percent style.  Tabs, formfeeds,
424            linefeeds and carriage returns are also escaped.
425            "percent+" also maps spaces to plus characters.
426
427    Example: get_var_ext ("get sysconfdir") -> "/etc/gnupg"
428     
429   */
430 static char *
431 get_var_ext (const char *name)
432 {
433   static int recursion_count;
434   const char *s;
435   char *result;
436   char *p;
437   char *free_me = NULL;
438
439   if (recursion_count > 50)
440     {
441       log_error ("variables nested too deeply\n");
442       return NULL;
443     }
444
445   recursion_count++;
446   free_me = opt.enable_varsubst? substitute_line_copy (name) : NULL;
447   if (free_me)
448     name = free_me;
449   for (s=name; *s && !spacep (s); s++)
450     ;
451   if (!*s)
452     {
453       s = get_var (name);
454       result = s? xstrdup (s): NULL;
455     }
456   else if ( (s - name) == 3 && !strncmp (name, "get", 3))
457     {
458       while ( spacep (s) )
459         s++;
460       if (!strcmp (s, "cwd"))
461         {
462           result = gnu_getcwd ();
463           if (!result)
464             log_error ("getcwd failed: %s\n", strerror (errno));
465         }
466       else if (!strcmp (s, "homedir"))
467         result = make_filename (opt.homedir, NULL);
468       else if (!strcmp (s, "sysconfdir"))
469         result = xstrdup (gnupg_sysconfdir ());
470       else if (!strcmp (s, "bindir"))
471         result = xstrdup (gnupg_bindir ());
472       else if (!strcmp (s, "libdir"))
473         result = xstrdup (gnupg_libdir ());
474       else if (!strcmp (s, "libexecdir"))
475         result = xstrdup (gnupg_libexecdir ());
476       else if (!strcmp (s, "datadir"))
477         result = xstrdup (gnupg_datadir ());
478       else if (!strcmp (s, "serverpid"))
479         {
480           char numbuf[30];
481           snprintf (numbuf, sizeof numbuf, "%d", (int)server_pid);
482           result = xstrdup (numbuf);
483         }
484       else
485         {
486           log_error ("invalid argument `%s' for variable function `get'\n", s);
487           log_info  ("valid are: cwd, "
488                      "{home,bin,lib,libexec,data}dir, serverpid\n");
489           result = NULL;
490         }
491     }
492   else if ( (s - name) == 8 && !strncmp (name, "unescape", 8))
493     {
494       s++;
495       result = unescape_string (s);
496     }
497   else if ( (s - name) == 9 && !strncmp (name, "unpercent", 9))
498     {
499       s++;
500       result = unpercent_string (s, 0);
501     }
502   else if ( (s - name) == 10 && !strncmp (name, "unpercent+", 10))
503     {
504       s++;
505       result = unpercent_string (s, 1);
506     }
507   else if ( (s - name) == 7 && !strncmp (name, "percent", 7))
508     {
509       s++;
510       result = percent_escape (s, "\t\r\n\f\v");
511     }
512   else if ( (s - name) == 8 && !strncmp (name, "percent+", 8))
513     {
514       s++;
515       result = percent_escape (s, "\t\r\n\f\v");
516       for (p=result; *p; p++)
517         if (*p == ' ')
518           *p = '+';
519     }
520   else
521     {
522       log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
523       result = NULL;
524     }
525     
526   xfree (free_me);
527   recursion_count--;
528   return result;
529 }
530
531
532 /* Substitute variables in LINE and return a new allocated buffer if
533    required.  The function might modify LINE if the expanded version
534    fits into it.  */
535 static char *
536 substitute_line (char *buffer)
537 {
538   char *line = buffer;
539   char *p, *pend;
540   const char *value;
541   size_t valuelen, n;
542   char *result = NULL;
543   char *freeme = NULL;
544
545   while (*line)
546     {
547       p = strchr (line, '$');
548       if (!p)
549         return result; /* No more variables.  */
550       
551       if (p[1] == '$') /* Escaped dollar sign. */
552         {
553           memmove (p, p+1, strlen (p+1)+1);
554           line = p + 1;
555           continue;
556         }
557       if (p[1] == '{')
558         {
559           int count = 0;
560
561           for (pend=p+2; *pend; pend++)
562             {
563               if (*pend == '{')
564                 count++;
565               else if (*pend == '}')
566                 {
567                   if (--count < 0)
568                     break;
569                 }
570             }
571           if (!*pend)
572             return result; /* Unclosed - don't substitute.  */
573         }
574       else
575         {
576           for (pend=p+1; *pend && !spacep (pend) && *pend != '$' ; pend++)
577             ;
578         }
579       if (p[1] == '{' && *pend == '}')
580         {
581           *pend++ = 0;
582           freeme = get_var_ext (p+2);
583           value = freeme;
584         }
585       else if (*pend)
586         {
587           int save = *pend;
588           *pend = 0;
589           value = get_var (p+1);
590           *pend = save;
591         }
592       else
593         value = get_var (p+1);
594       if (!value)
595         value = "";
596       valuelen = strlen (value);
597       if (valuelen <= pend - p)
598         {
599           memcpy (p, value, valuelen);
600           p += valuelen;
601           n = pend - p;
602           if (n)
603             memmove (p, p+n, strlen (p+n)+1);
604           line = p;
605         }
606       else
607         {
608           char *src = result? result : buffer;
609           char *dst;
610
611           dst = xmalloc (strlen (src) + valuelen + 1);
612           n = p - src;
613           memcpy (dst, src, n);
614           memcpy (dst + n, value, valuelen);
615           n += valuelen;
616           strcpy (dst + n, pend);
617           line = dst + n;
618           free (result);
619           result = dst;
620         }
621       xfree (freeme);
622       freeme = NULL;
623     }
624   return result;
625 }
626
627 /* Same as substitute_line but do not modify BUFFER.  */
628 static char *
629 substitute_line_copy (const char *buffer)
630 {
631   char *result, *p;
632   
633   p = xstrdup (buffer?buffer:"");
634   result = substitute_line (p);
635   if (!result)
636     result = p;
637   else
638     xfree (p);
639   return result;
640 }
641
642
643 static void
644 assign_variable (char *line, int syslet)
645 {
646   char *name, *p, *tmp, *free_me, *buffer;
647
648   /* Get the  name. */
649   name = line;
650   for (p=name; *p && !spacep (p); p++)
651     ;
652   if (*p)
653     *p++ = 0;
654   while (spacep (p))
655     p++;
656
657   if (!*p)
658     set_var (name, NULL); /* Remove variable.  */ 
659   else if (syslet)
660     {
661       free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL;
662       if (free_me)
663         p = free_me;
664       buffer = xmalloc (4 + strlen (p) + 1);
665       strcpy (stpcpy (buffer, "get "), p);
666       tmp = get_var_ext (buffer);
667       xfree (buffer);
668       set_var (name, tmp);
669       xfree (tmp);
670       xfree (free_me);
671     }
672   else 
673     {
674       tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
675       if (tmp)
676         {
677           set_var (name, tmp);
678           xfree (tmp);
679         }
680       else
681         set_var (name, p);
682     }
683 }
684
685
686 static void
687 show_variables (void)
688 {
689   variable_t var;
690
691   for (var = variable_table; var; var = var->next)
692     if (var->value)
693       printf ("%-20s %s\n", var->name, var->value);
694 }
695
696
697 /* Store an inquire response pattern.  Note, that this function may
698    change the content of LINE.  We assume that leading white spaces
699    are already removed. */
700 static void
701 add_definq (char *line, int is_var, int is_prog)
702 {
703   definq_t d;
704   char *name, *p;
705
706   /* Get name. */
707   name = line;
708   for (p=name; *p && !spacep (p); p++)
709     ;
710   if (*p)
711     *p++ = 0;
712   while (spacep (p))
713     p++;
714
715   d = xmalloc (sizeof *d + strlen (p) );
716   strcpy (d->file, p);
717   d->is_var  = is_var;
718   d->is_prog = is_prog;
719   if ( !strcmp (name, "*"))
720     d->name = NULL;
721   else
722     d->name = xstrdup (name);
723
724   d->next = NULL;
725   *definq_list_tail = d;
726   definq_list_tail = &d->next;
727 }
728
729
730 /* Show all inquiry defintions. */
731 static void
732 show_definq (void)
733 {
734   definq_t d;
735
736   for (d=definq_list; d; d = d->next)
737     if (d->name)
738       printf ("%-20s %c %s\n", 
739               d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file);
740   for (d=definq_list; d; d = d->next)
741     if (!d->name)
742       printf ("%-20s %c %s\n", "*", 
743               d->is_var? 'v': d->is_prog? 'p':'f', d->file);
744 }
745
746
747 /* Clear all inquiry definitions. */
748 static void
749 clear_definq (void)
750 {
751   while (definq_list)
752     { 
753       definq_t tmp = definq_list->next;
754       xfree (definq_list->name);
755       xfree (definq_list);
756       definq_list = tmp;
757     }
758   definq_list_tail = &definq_list;
759 }      
760
761
762 static void
763 do_sendfd (assuan_context_t ctx, char *line)
764 {
765   FILE *fp;
766   char *name, *mode, *p;
767   int rc, fd;
768
769   /* Get file name. */
770   name = line;
771   for (p=name; *p && !spacep (p); p++)
772     ;
773   if (*p)
774     *p++ = 0;
775   while (spacep (p))
776     p++;
777
778   /* Get mode.  */
779   mode = p;
780   if (!*mode)
781     mode = "r";
782   else
783     {
784       for (p=mode; *p && !spacep (p); p++)
785         ;
786       if (*p)
787         *p++ = 0;
788     }
789
790   /* Open and send. */
791   fp = fopen (name, mode);
792   if (!fp)
793     {
794       log_error ("can't open `%s' in \"%s\" mode: %s\n",
795                  name, mode, strerror (errno));
796       return;
797     }
798   fd = fileno (fp);
799
800   if (opt.verbose)
801     log_error ("file `%s' opened in \"%s\" mode, fd=%d\n",
802                name, mode, fd);
803
804   rc = assuan_sendfd (ctx, INT2FD (fd) );
805   if (rc)
806     log_error ("sending descriptor %d failed: %s\n", fd, gpg_strerror (rc));
807   fclose (fp);
808 }
809
810
811 static void
812 do_recvfd (assuan_context_t ctx, char *line)
813 {
814   log_info ("This command has not yet been implemented\n");
815 }
816
817
818 static void
819 do_open (char *line)
820 {
821   FILE *fp;
822   char *varname, *name, *mode, *p;
823   int fd;
824
825 #ifdef HAVE_W32_SYSTEM
826   if (server_pid == (pid_t)(-1))
827     {
828       log_error ("the pid of the server is unknown\n");
829       log_info ("use command \"/serverpid\" first\n");
830       return;
831     }
832 #endif
833
834   /* Get variable name. */
835   varname = line;
836   for (p=varname; *p && !spacep (p); p++)
837     ;
838   if (*p)
839     *p++ = 0;
840   while (spacep (p))
841     p++;
842
843   /* Get file name. */
844   name = p;
845   for (p=name; *p && !spacep (p); p++)
846     ;
847   if (*p)
848     *p++ = 0;
849   while (spacep (p))
850     p++;
851
852   /* Get mode.  */
853   mode = p;
854   if (!*mode)
855     mode = "r";
856   else
857     {
858       for (p=mode; *p && !spacep (p); p++)
859         ;
860       if (*p)
861         *p++ = 0;
862     }
863
864   /* Open and send. */
865   fp = fopen (name, mode);
866   if (!fp)
867     {
868       log_error ("can't open `%s' in \"%s\" mode: %s\n",
869                  name, mode, strerror (errno));
870       return;
871     }
872   fd = fileno (fp);
873   if (fd >= 0 && fd < DIM (open_fd_table))
874     {
875       open_fd_table[fd].inuse = 1;
876 #ifdef HAVE_W32_SYSTEM
877       {
878         HANDLE prochandle, handle, newhandle;
879
880         handle = (void*)_get_osfhandle (fd);
881      
882         prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid);
883         if (!prochandle)
884           {
885             log_error ("failed to open the server process\n");
886             close (fd);
887             return;
888           }
889
890         if (!DuplicateHandle (GetCurrentProcess(), handle,
891                               prochandle, &newhandle, 0,
892                               TRUE, DUPLICATE_SAME_ACCESS ))
893           {
894             log_error ("failed to duplicate the handle\n");
895             close (fd);
896             CloseHandle (prochandle);
897             return;
898           }
899         CloseHandle (prochandle);
900         open_fd_table[fd].handle = newhandle;
901       }
902       if (opt.verbose)
903         log_info ("file `%s' opened in \"%s\" mode, fd=%d  (libc=%d)\n",
904                    name, mode, (int)open_fd_table[fd].handle, fd);
905       set_int_var (varname, (int)open_fd_table[fd].handle);
906 #else  
907       if (opt.verbose)
908         log_info ("file `%s' opened in \"%s\" mode, fd=%d\n",
909                    name, mode, fd);
910       set_int_var (varname, fd);
911 #endif
912     }
913   else
914     {
915       log_error ("can't put fd %d into table\n", fd);
916       close (fd);
917     }
918 }
919
920
921 static void
922 do_close (char *line)
923 {
924   int fd = atoi (line);
925
926 #ifdef HAVE_W32_SYSTEM
927   int i;
928
929   for (i=0; i < DIM (open_fd_table); i++)
930     if ( open_fd_table[i].inuse && open_fd_table[i].handle == (void*)fd)
931       break;
932   if (i < DIM (open_fd_table))
933     fd = i;
934   else
935     {
936       log_error ("given fd (system handle) has not been opened\n");
937       return;
938     }
939 #endif
940
941   if (fd < 0 || fd >= DIM (open_fd_table))
942     {
943       log_error ("invalid fd\n");
944       return;
945     }
946
947   if (!open_fd_table[fd].inuse)
948     {
949       log_error ("given fd has not been opened\n");
950       return;
951     }
952 #ifdef HAVE_W32_SYSTEM
953   CloseHandle (open_fd_table[fd].handle); /* Close duped handle.  */
954 #endif
955   close (fd);
956   open_fd_table[fd].inuse = 0;
957 }
958
959
960 static void
961 do_showopen (void)
962 {
963   int i;
964
965   for (i=0; i < DIM (open_fd_table); i++)
966     if (open_fd_table[i].inuse)
967       {
968 #ifdef HAVE_W32_SYSTEM
969         printf ("%-15d (libc=%d)\n", (int)open_fd_table[i].handle, i);
970 #else
971         printf ("%-15d\n", i);
972 #endif
973       }
974 }
975
976
977
978 static int
979 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
980 {
981   membuf_t *mb = opaque;
982   put_membuf (mb, buffer, length);
983   return 0;
984 }
985
986 /* Get the pid of the server and store it locally.  */
987 static void
988 do_serverpid (assuan_context_t ctx)
989 {
990   int rc;
991   membuf_t mb;
992   char *buffer;
993   
994   init_membuf (&mb, 100);
995   rc = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, &mb,
996                         NULL, NULL, NULL, NULL);
997   put_membuf (&mb, "", 1);
998   buffer = get_membuf (&mb, NULL);
999   if (rc || !buffer)
1000     log_error ("command \"%s\" failed: %s\n", 
1001                "GETINFO pid", gpg_strerror (rc));
1002   else
1003     {
1004       server_pid = (pid_t)strtoul (buffer, NULL, 10);
1005       if (opt.verbose)
1006         log_info ("server's PID is %lu\n", (unsigned long)server_pid);
1007     }
1008   xfree (buffer);
1009 }
1010
1011
1012 /* gpg-connect-agent's entry point. */
1013 int
1014 main (int argc, char **argv)
1015 {
1016   ARGPARSE_ARGS pargs;
1017   int no_more_options = 0;
1018   assuan_context_t ctx;
1019   char *line, *p;
1020   char *tmpline;
1021   size_t linesize;
1022   int rc;
1023   int cmderr;
1024   const char *opt_run = NULL;
1025   FILE *script_fp = NULL;
1026   int use_tty, last_was_tty;
1027
1028
1029   gnupg_rl_initialize ();
1030   set_strusage (my_strusage);
1031   log_set_prefix ("gpg-connect-agent", 1);
1032
1033   /* Make sure that our subsystems are ready.  */
1034   init_common_subsystems ();
1035
1036   assuan_set_assuan_err_source (0);
1037
1038   i18n_init();
1039
1040   opt.homedir = default_homedir ();
1041   opt.connect_flags = 1; /* Use extended connect mode.  */
1042
1043   /* Parse the command line. */
1044   pargs.argc  = &argc;
1045   pargs.argv  = &argv;
1046   pargs.flags =  1;  /* Do not remove the args.  */
1047   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
1048     {
1049       switch (pargs.r_opt)
1050         {
1051         case oQuiet:     opt.quiet = 1; break;
1052         case oVerbose:   opt.verbose++; break;
1053         case oNoVerbose: opt.verbose = 0; break;
1054         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
1055         case oHex:       opt.hex = 1; break;
1056         case oDecode:    opt.decode = 1; break;
1057         case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
1058         case oExec:      opt.exec = 1; break;
1059         case oNoExtConnect: opt.connect_flags &= ~(1); break;
1060         case oRun:       opt_run = pargs.r.ret_str; break;
1061         case oSubst:     opt.enable_varsubst = 1; break;
1062
1063         default: pargs.err = 2; break;
1064         }
1065     }
1066
1067   if (log_get_errorcount (0))
1068     exit (2);
1069
1070   use_tty = (isatty ( fileno (stdin)) && isatty (fileno (stdout)));
1071
1072   if (opt.exec)
1073     {
1074       if (!argc)
1075         {
1076           log_error (_("option \"%s\" requires a program "
1077                        "and optional arguments\n"), "--exec" );
1078           exit (1);
1079         }
1080     }
1081   else if (argc)
1082     usage (1);
1083
1084   if (opt.exec && opt.raw_socket)
1085     log_info (_("option \"%s\" ignored due to \"%s\"\n"),
1086               "--raw-socket", "--exec");
1087
1088   if (opt_run && !(script_fp = fopen (opt_run, "r")))
1089     {
1090       log_error ("cannot open run file `%s': %s\n",
1091                  opt_run, strerror (errno));
1092       exit (1);
1093     }
1094
1095
1096   if (opt.exec)
1097     {
1098       int no_close[3];
1099
1100       no_close[0] = fileno (stderr);
1101       no_close[1] = log_get_fd ();
1102       no_close[2] = -1;
1103       rc = assuan_pipe_connect_ext (&ctx, *argv, (const char **)argv,
1104                                     no_close, NULL, NULL,
1105                                     opt.connect_flags);
1106       if (rc)
1107         {
1108           log_error ("assuan_pipe_connect_ext failed: %s\n",
1109                      gpg_strerror (rc));
1110           exit (1);
1111         }
1112
1113       if (opt.verbose)
1114         log_info ("server `%s' started\n", *argv);
1115
1116     }
1117   else if (opt.raw_socket)
1118     {
1119       rc = assuan_socket_connect_ext (&ctx, opt.raw_socket, 0,
1120                                       opt.connect_flags);
1121       if (rc)
1122         {
1123           log_error ("can't connect to socket `%s': %s\n",
1124                      opt.raw_socket, gpg_strerror (rc));
1125           exit (1);
1126         }
1127
1128       if (opt.verbose)
1129         log_info ("connection to socket `%s' established\n", opt.raw_socket);
1130     }
1131   else
1132     ctx = start_agent ();
1133
1134   /* See whether there is a line pending from the server (in case
1135      assuan did not run the initial handshaking).  */
1136   if (assuan_pending_line (ctx))
1137     {
1138       rc = read_and_print_response (ctx, &cmderr);
1139       if (rc)
1140         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1141     }
1142
1143  
1144   line = NULL;
1145   linesize = 0;
1146   last_was_tty = 0;
1147   for (;;)
1148     {
1149       int n;
1150       size_t maxlength;
1151
1152       maxlength = 2048;
1153       if (use_tty && !script_fp)
1154         {
1155           last_was_tty = 1;
1156           line = tty_get ("> ");
1157           n = strlen (line);
1158           if (n==1 && *line == CONTROL_D)
1159             n = 0;
1160           if (n >= maxlength)
1161             maxlength = 0;
1162         }
1163       else
1164         {
1165           if (last_was_tty)
1166             {
1167               xfree (line);
1168               line = NULL;
1169               linesize = 0;
1170               last_was_tty = 0;
1171             }
1172           n = read_line (script_fp? script_fp:stdin, 
1173                          &line, &linesize, &maxlength);
1174         }
1175       if (n < 0)
1176         {
1177           log_error (_("error reading input: %s\n"), strerror (errno));
1178           if (script_fp)
1179             {
1180               fclose (script_fp);
1181               script_fp = NULL;
1182               log_error ("stopping script execution\n");
1183               continue;
1184             }
1185           exit (1);
1186         }
1187       if (!n)
1188         {
1189           /* EOF */
1190           if (script_fp)
1191             {
1192               fclose (script_fp);
1193               script_fp = NULL;
1194               if (opt.verbose)
1195                 log_info ("end of script\n");
1196               continue;
1197             }
1198           break; 
1199         }
1200       if (!maxlength)
1201         {
1202           log_error (_("line too long - skipped\n"));
1203           continue;
1204         }
1205       if (memchr (line, 0, n))
1206         log_info (_("line shortened due to embedded Nul character\n"));
1207       if (line[n-1] == '\n')
1208         line[n-1] = 0;
1209       if (*line == '/')
1210         {
1211           /* Handle control commands. */
1212           char *cmd = line+1;
1213
1214           for (p=cmd; *p && !spacep (p); p++)
1215             ;
1216           if (*p)
1217             *p++ = 0;
1218           while (spacep (p))
1219             p++;
1220           if (!strcmp (cmd, "let"))
1221             {
1222               assign_variable (p, 0);
1223             }
1224           else if (!strcmp (cmd, "slet"))
1225             {
1226               /* Deprecated - never used in a released version.  */
1227               assign_variable (p, 1);
1228             }
1229           else if (!strcmp (cmd, "showvar"))
1230             {
1231               show_variables ();
1232             }
1233           else if (!strcmp (cmd, "definq"))
1234             {
1235               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1236               if (tmpline)
1237                 {
1238                   add_definq (tmpline, 1, 0);
1239                   xfree (tmpline);
1240                 }
1241               else
1242                 add_definq (p, 1, 0);
1243             }
1244           else if (!strcmp (cmd, "definqfile"))
1245             {
1246               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1247               if (tmpline)
1248                 {
1249                   add_definq (tmpline, 0, 0);
1250                   xfree (tmpline);
1251                 }
1252               else
1253                 add_definq (p, 0, 0);
1254             }
1255           else if (!strcmp (cmd, "definqprog"))
1256             {
1257               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1258               if (tmpline)
1259                 {
1260                   add_definq (tmpline, 0, 1);
1261                   xfree (tmpline);
1262                 }
1263               else
1264                 add_definq (p, 0, 1);
1265             }
1266           else if (!strcmp (cmd, "showdef"))
1267             {
1268               show_definq ();
1269             }
1270           else if (!strcmp (cmd, "cleardef"))
1271             {
1272               clear_definq ();
1273             }
1274           else if (!strcmp (cmd, "echo"))
1275             {
1276               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1277               if (tmpline)
1278                 {
1279                   puts (tmpline);
1280                   xfree (tmpline);
1281                 }
1282               else
1283                 puts (p);
1284             }
1285           else if (!strcmp (cmd, "sendfd"))
1286             {
1287               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1288               if (tmpline)
1289                 {
1290                   do_sendfd (ctx, tmpline);
1291                   xfree (tmpline);
1292                 }
1293               else
1294                 do_sendfd (ctx, p);
1295               continue;
1296             }
1297           else if (!strcmp (cmd, "recvfd"))
1298             {
1299               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1300               if (tmpline)
1301                 {
1302                   do_recvfd (ctx, tmpline);
1303                   xfree (tmpline);
1304                 }
1305               else
1306                 do_recvfd (ctx, p);
1307               continue;
1308             }
1309           else if (!strcmp (cmd, "open"))
1310             {
1311               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1312               if (tmpline)
1313                 {
1314                   do_open (tmpline);
1315                   xfree (tmpline);
1316                 }
1317               else
1318                 do_open (p);
1319             }
1320           else if (!strcmp (cmd, "close"))
1321             {
1322               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1323               if (tmpline)
1324                 {
1325                   do_close (tmpline);
1326                   xfree (tmpline);
1327                 }
1328               else
1329                 do_close (p);
1330             }
1331           else if (!strcmp (cmd, "showopen"))
1332             {
1333               do_showopen ();
1334             }
1335           else if (!strcmp (cmd, "serverpid"))
1336             {
1337               do_serverpid (ctx);
1338             }
1339           else if (!strcmp (cmd, "hex"))
1340             opt.hex = 1;
1341           else if (!strcmp (cmd, "nohex"))
1342             opt.hex = 0;
1343           else if (!strcmp (cmd, "decode"))
1344             opt.decode = 1;
1345           else if (!strcmp (cmd, "nodecode"))
1346             opt.decode = 0;
1347           else if (!strcmp (cmd, "subst"))
1348             opt.enable_varsubst = 1;
1349           else if (!strcmp (cmd, "nosubst"))
1350             opt.enable_varsubst = 0;
1351           else if (!strcmp (cmd, "run"))
1352             {
1353               char *p2;
1354               for (p2=p; *p2 && !spacep (p2); p2++)
1355                 ;
1356               if (*p2)
1357                 *p2++ = 0;
1358               while (spacep (p2))
1359                 p++;
1360               if (*p2)
1361                 {
1362                   log_error ("syntax error in run command\n");
1363                   if (script_fp)
1364                     {
1365                       fclose (script_fp);
1366                       script_fp = NULL;
1367                     }
1368                 }
1369               else if (script_fp)
1370                 {
1371                   log_error ("cannot nest run commands - stop\n");
1372                   fclose (script_fp);
1373                   script_fp = NULL;
1374                 }
1375               else if (!(script_fp = fopen (p, "r")))
1376                 {
1377                   log_error ("cannot open run file `%s': %s\n",
1378                              p, strerror (errno));
1379                 }
1380               else if (opt.verbose)
1381                 log_info ("running commands from `%s'\n", p);
1382             }
1383           else if (!strcmp (cmd, "bye"))
1384             {
1385               break;
1386             }
1387           else if (!strcmp (cmd, "help"))
1388             {
1389               puts (
1390 "Available commands:\n"
1391 "/echo ARGS             Echo ARGS.\n"
1392 "/let  NAME VALUE       Set variable NAME to VALUE.\n"
1393 "/showvar               Show all variables.\n"
1394 "/definq NAME VAR       Use content of VAR for inquiries with NAME.\n"
1395 "/definqfile NAME FILE  Use content of FILE for inquiries with NAME.\n"
1396 "/definqprog NAME PGM   Run PGM for inquiries with NAME.\n"
1397 "/showdef               Print all definitions.\n"
1398 "/cleardef              Delete all definitions.\n"
1399 "/sendfd FILE MODE      Open FILE and pass descriptor to server.\n"
1400 "/recvfd                Receive FD from server and print.\n"
1401 "/open VAR FILE MODE    Open FILE and assign the file descriptor to VAR.\n" 
1402 "/close FD              Close file with descriptor FD.\n"
1403 "/showopen              Show descriptors of all open files.\n"
1404 "/serverpid             Retrieve the pid of the server.\n"
1405 "/[no]hex               Enable hex dumping of received data lines.\n"
1406 "/[no]decode            Enable decoding of received data lines.\n"
1407 "/[no]subst             Enable varibale substitution.\n"
1408 "/run FILE              Run commands from FILE.\n"
1409 "/bye                   Terminate gpg-connect-agent.\n"
1410 "/help                  Print this help.");
1411             }
1412           else
1413             log_error (_("unknown command `%s'\n"), cmd );
1414       
1415           continue;
1416         }
1417
1418       if (opt.verbose && script_fp)
1419         puts (line);
1420
1421       tmpline = opt.enable_varsubst? substitute_line (line) : NULL;
1422       if (tmpline)
1423         {
1424           rc = assuan_write_line (ctx, tmpline);
1425           xfree (tmpline);
1426         }
1427       else
1428         rc = assuan_write_line (ctx, line);
1429       if (rc)
1430         {
1431           log_info (_("sending line failed: %s\n"), gpg_strerror (rc) );
1432           break;
1433         }
1434       if (*line == '#' || !*line)
1435         continue; /* Don't expect a response for a comment line. */
1436
1437       rc = read_and_print_response (ctx, &cmderr);
1438       if (rc)
1439         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1440       if ((rc || cmderr) && script_fp)
1441         {
1442           log_error ("stopping script execution\n");
1443           fclose (script_fp);
1444           script_fp = NULL;
1445         }
1446           
1447
1448       /* FIXME: If the last command was BYE or the server died for
1449          some other reason, we won't notice until we get the next
1450          input command.  Probing the connection with a non-blocking
1451          read could help to notice termination or other problems
1452          early.  */
1453     }
1454
1455   if (opt.verbose)
1456     log_info ("closing connection to agent\n");
1457   
1458   return 0; 
1459 }
1460
1461
1462 /* Handle an Inquire from the server.  Return False if it could not be
1463    handled; in this case the caller shll complete the operation.  LINE
1464    is the complete line as received from the server.  This function
1465    may change the content of LINE. */
1466 static int
1467 handle_inquire (assuan_context_t ctx, char *line)
1468 {
1469   const char *name;
1470   definq_t d;
1471   FILE *fp = NULL;
1472   char buffer[1024];
1473   int rc, n;
1474
1475   /* Skip the command and trailing spaces. */
1476   for (; *line && !spacep (line); line++)
1477     ;
1478   while (spacep (line))
1479     line++;
1480   /* Get the name. */
1481   name = line;
1482   for (; *line && !spacep (line); line++)
1483     ;
1484   if (*line)
1485     *line++ = 0;
1486
1487   /* Now match it against our list. he second loop is todetect the
1488      match all entry. **/
1489   for (d=definq_list; d; d = d->next)
1490     if (d->name && !strcmp (d->name, name))
1491         break;
1492   if (!d)
1493     for (d=definq_list; d; d = d->next)
1494       if (!d->name)
1495         break;
1496   if (!d)
1497     {
1498       if (opt.verbose)
1499         log_info ("no handler for inquiry `%s' found\n", name);
1500       return 0;
1501     }
1502
1503   if (d->is_var)
1504     {
1505       char *tmpvalue = get_var_ext (d->file);
1506       rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue));
1507       xfree (tmpvalue);
1508       if (rc)
1509         log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1510     }
1511   else
1512     {
1513       if (d->is_prog)
1514         {
1515           fp = popen (d->file, "r");
1516           if (!fp)
1517             log_error ("error executing `%s': %s\n",
1518                        d->file, strerror (errno));
1519           else if (opt.verbose)
1520             log_error ("handling inquiry `%s' by running `%s'\n", 
1521                        name, d->file);
1522         }
1523       else
1524         {
1525           fp = fopen (d->file, "rb");
1526           if (!fp)
1527             log_error ("error opening `%s': %s\n", d->file, strerror (errno));
1528           else if (opt.verbose)
1529             log_error ("handling inquiry `%s' by returning content of `%s'\n",
1530                        name, d->file);
1531         }
1532       if (!fp)
1533         return 0;
1534
1535       while ( (n = fread (buffer, 1, sizeof buffer, fp)) )
1536         {
1537           rc = assuan_send_data (ctx, buffer, n);
1538           if (rc)
1539             {
1540               log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1541               break;
1542             }
1543         }
1544       if (ferror (fp))
1545         log_error ("error reading from `%s': %s\n", d->file, strerror (errno));
1546     }
1547
1548   rc = assuan_send_data (ctx, NULL, 0);
1549   if (rc)
1550     log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1551
1552   if (d->is_var)
1553     ;
1554   else if (d->is_prog)
1555     {
1556       if (pclose (fp))
1557         log_error ("error running `%s': %s\n", d->file, strerror (errno));
1558     }
1559   else
1560     fclose (fp);
1561   return 1;
1562 }
1563
1564
1565 /* Read all response lines from server and print them.  Returns 0 on
1566    success or an assuan error code.  Set R_GOTERR to true if the
1567    command did not returned OK.  */
1568 static int
1569 read_and_print_response (assuan_context_t ctx, int *r_goterr)
1570 {
1571   char *line;
1572   size_t linelen;
1573   assuan_error_t rc;
1574   int i, j;
1575   int need_lf = 0;
1576
1577   *r_goterr = 0;
1578   for (;;)
1579     {
1580       do 
1581         {
1582           rc = assuan_read_line (ctx, &line, &linelen);
1583           if (rc)
1584             return rc;
1585
1586           if (opt.verbose > 1 && *line == '#')
1587             {
1588               fwrite (line, linelen, 1, stdout);
1589               putchar ('\n');
1590             }
1591         }    
1592       while (*line == '#' || !linelen);
1593
1594       if (linelen >= 1
1595           && line[0] == 'D' && line[1] == ' ')
1596         {
1597           if (opt.hex)
1598             {
1599               for (i=2; i < linelen; )
1600                 {
1601                   int save_i = i;
1602
1603                   printf ("D[%04X] ", i-2);
1604                   for (j=0; j < 16 ; j++, i++)
1605                     {
1606                       if (j == 8)
1607                         putchar (' ');
1608                       if (i < linelen)
1609                         printf (" %02X", ((unsigned char*)line)[i]);
1610                       else
1611                         fputs ("   ", stdout);
1612                     }
1613                   fputs ("   ", stdout);
1614                   i= save_i;
1615                   for (j=0; j < 16; j++, i++)
1616                     {
1617                       unsigned int c = ((unsigned char*)line)[i];
1618                       if ( i >= linelen )
1619                         putchar (' ');
1620                       else if (isascii (c) && isprint (c) && !iscntrl (c))
1621                         putchar (c);
1622                       else
1623                         putchar ('.');
1624                     }
1625                   putchar ('\n');
1626                 }
1627             }
1628           else if (opt.decode)
1629             {
1630               const unsigned char *s;
1631               int need_d = 1;
1632               int c = 0;
1633
1634               for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
1635                 {
1636                   if (need_d)
1637                     {
1638                       fputs ("D ", stdout);
1639                       need_d = 0;
1640                     }
1641                   if (*s == '%' && j+2 < linelen)
1642                     { 
1643                       s++; j++;
1644                       c = xtoi_2 ( s );
1645                       s++; j++;
1646                     }
1647                   else
1648                     c = *s;
1649                   if (c == '\n')
1650                     need_d = 1;
1651                   putchar (c);
1652                 }
1653               need_lf = (c != '\n');
1654             }
1655           else
1656             {
1657               fwrite (line, linelen, 1, stdout);
1658               putchar ('\n');
1659             }
1660         }
1661       else 
1662         {
1663           if (need_lf)
1664             {
1665               putchar ('\n');
1666               need_lf = 0;
1667             }
1668
1669           if (linelen >= 1
1670               && line[0] == 'S' 
1671               && (line[1] == '\0' || line[1] == ' '))
1672             {
1673               fwrite (line, linelen, 1, stdout);
1674               putchar ('\n');
1675             }  
1676           else if (linelen >= 2
1677                    && line[0] == 'O' && line[1] == 'K'
1678                    && (line[2] == '\0' || line[2] == ' '))
1679             {
1680               fwrite (line, linelen, 1, stdout);
1681               putchar ('\n');
1682               return 0;
1683             }
1684           else if (linelen >= 3
1685                    && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
1686                    && (line[3] == '\0' || line[3] == ' '))
1687             {
1688               fwrite (line, linelen, 1, stdout);
1689               putchar ('\n');
1690               *r_goterr = 1;
1691               return 0;
1692             }  
1693           else if (linelen >= 7
1694                    && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1695                    && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1696                    && line[6] == 'E' 
1697                    && (line[7] == '\0' || line[7] == ' '))
1698             {
1699               fwrite (line, linelen, 1, stdout);
1700               putchar ('\n');
1701               if (!handle_inquire (ctx, line))
1702                 assuan_write_line (ctx, "CANCEL");
1703             }
1704           else if (linelen >= 3
1705                    && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
1706                    && (line[3] == '\0' || line[3] == ' '))
1707             {
1708               fwrite (line, linelen, 1, stdout);
1709               putchar ('\n');
1710               /* Received from server, thus more responses are expected.  */
1711             }
1712           else
1713             return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
1714         }
1715     }
1716 }
1717
1718
1719
1720
1721 /* Connect to the agent and send the standard options.  */
1722 static assuan_context_t
1723 start_agent (void)
1724 {
1725   int rc = 0;
1726   char *infostr, *p;
1727   assuan_context_t ctx;
1728
1729   infostr = getenv ("GPG_AGENT_INFO");
1730   if (!infostr || !*infostr)
1731     {
1732       char *sockname;
1733
1734       /* Check whether we can connect at the standard socket.  */
1735       sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
1736       rc = assuan_socket_connect (&ctx, sockname, 0);
1737       xfree (sockname);
1738     }
1739   else
1740     {
1741       int prot;
1742       int pid;
1743
1744       infostr = xstrdup (infostr);
1745       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
1746         {
1747           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
1748           xfree (infostr);
1749           exit (1);
1750         }
1751       *p++ = 0;
1752       pid = atoi (p);
1753       while (*p && *p != PATHSEP_C)
1754         p++;
1755       prot = *p? atoi (p+1) : 0;
1756       if (prot != 1)
1757         {
1758           log_error (_("gpg-agent protocol version %d is not supported\n"),
1759                      prot);
1760           xfree (infostr);
1761           exit (1);
1762         }
1763
1764       rc = assuan_socket_connect (&ctx, infostr, pid);
1765       xfree (infostr);
1766     }
1767
1768   if (rc)
1769     {
1770       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
1771       exit (1);
1772     }
1773
1774   if (opt.verbose)
1775     log_info ("connection to agent established\n");
1776
1777   rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1778   if (rc)
1779     {
1780       log_error (_("error sending %s command: %s\n"), "RESET", 
1781                  gpg_strerror (rc));
1782       exit (1);
1783     }
1784
1785   rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
1786                                   NULL, NULL, NULL, NULL, NULL);
1787   if (rc)
1788     {
1789       log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
1790       exit (1);
1791     }
1792
1793   return ctx;
1794 }