Changed wording of passphrase checking messages.
[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           int save = *pend;
582           *pend = 0;
583           freeme = get_var_ext (p+2);
584           value = freeme;
585           *pend++ = save;
586         }
587       else if (*pend)
588         {
589           int save = *pend;
590           *pend = 0;
591           value = get_var (p+1);
592           *pend = save;
593         }
594       else
595         value = get_var (p+1);
596       if (!value)
597         value = "";
598       valuelen = strlen (value);
599       if (valuelen <= pend - p)
600         {
601           memcpy (p, value, valuelen);
602           p += valuelen;
603           n = pend - p;
604           if (n)
605             memmove (p, p+n, strlen (p+n)+1);
606           line = p;
607         }
608       else
609         {
610           char *src = result? result : buffer;
611           char *dst;
612
613           dst = xmalloc (strlen (src) + valuelen + 1);
614           n = p - src;
615           memcpy (dst, src, n);
616           memcpy (dst + n, value, valuelen);
617           n += valuelen;
618           strcpy (dst + n, pend);
619           line = dst + n;
620           xfree (result);
621           result = dst;
622         }
623       xfree (freeme);
624       freeme = NULL;
625     }
626   return result;
627 }
628
629 /* Same as substitute_line but do not modify BUFFER.  */
630 static char *
631 substitute_line_copy (const char *buffer)
632 {
633   char *result, *p;
634   
635   p = xstrdup (buffer?buffer:"");
636   result = substitute_line (p);
637   if (!result)
638     result = p;
639   else
640     xfree (p);
641   return result;
642 }
643
644
645 static void
646 assign_variable (char *line, int syslet)
647 {
648   char *name, *p, *tmp, *free_me, *buffer;
649
650   /* Get the  name. */
651   name = line;
652   for (p=name; *p && !spacep (p); p++)
653     ;
654   if (*p)
655     *p++ = 0;
656   while (spacep (p))
657     p++;
658
659   if (!*p)
660     set_var (name, NULL); /* Remove variable.  */ 
661   else if (syslet)
662     {
663       free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL;
664       if (free_me)
665         p = free_me;
666       buffer = xmalloc (4 + strlen (p) + 1);
667       strcpy (stpcpy (buffer, "get "), p);
668       tmp = get_var_ext (buffer);
669       xfree (buffer);
670       set_var (name, tmp);
671       xfree (tmp);
672       xfree (free_me);
673     }
674   else 
675     {
676       tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
677       if (tmp)
678         {
679           set_var (name, tmp);
680           xfree (tmp);
681         }
682       else
683         set_var (name, p);
684     }
685 }
686
687
688 static void
689 show_variables (void)
690 {
691   variable_t var;
692
693   for (var = variable_table; var; var = var->next)
694     if (var->value)
695       printf ("%-20s %s\n", var->name, var->value);
696 }
697
698
699 /* Store an inquire response pattern.  Note, that this function may
700    change the content of LINE.  We assume that leading white spaces
701    are already removed. */
702 static void
703 add_definq (char *line, int is_var, int is_prog)
704 {
705   definq_t d;
706   char *name, *p;
707
708   /* Get name. */
709   name = line;
710   for (p=name; *p && !spacep (p); p++)
711     ;
712   if (*p)
713     *p++ = 0;
714   while (spacep (p))
715     p++;
716
717   d = xmalloc (sizeof *d + strlen (p) );
718   strcpy (d->file, p);
719   d->is_var  = is_var;
720   d->is_prog = is_prog;
721   if ( !strcmp (name, "*"))
722     d->name = NULL;
723   else
724     d->name = xstrdup (name);
725
726   d->next = NULL;
727   *definq_list_tail = d;
728   definq_list_tail = &d->next;
729 }
730
731
732 /* Show all inquiry defintions. */
733 static void
734 show_definq (void)
735 {
736   definq_t d;
737
738   for (d=definq_list; d; d = d->next)
739     if (d->name)
740       printf ("%-20s %c %s\n", 
741               d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file);
742   for (d=definq_list; d; d = d->next)
743     if (!d->name)
744       printf ("%-20s %c %s\n", "*", 
745               d->is_var? 'v': d->is_prog? 'p':'f', d->file);
746 }
747
748
749 /* Clear all inquiry definitions. */
750 static void
751 clear_definq (void)
752 {
753   while (definq_list)
754     { 
755       definq_t tmp = definq_list->next;
756       xfree (definq_list->name);
757       xfree (definq_list);
758       definq_list = tmp;
759     }
760   definq_list_tail = &definq_list;
761 }      
762
763
764 static void
765 do_sendfd (assuan_context_t ctx, char *line)
766 {
767   FILE *fp;
768   char *name, *mode, *p;
769   int rc, fd;
770
771   /* Get file name. */
772   name = line;
773   for (p=name; *p && !spacep (p); p++)
774     ;
775   if (*p)
776     *p++ = 0;
777   while (spacep (p))
778     p++;
779
780   /* Get mode.  */
781   mode = p;
782   if (!*mode)
783     mode = "r";
784   else
785     {
786       for (p=mode; *p && !spacep (p); p++)
787         ;
788       if (*p)
789         *p++ = 0;
790     }
791
792   /* Open and send. */
793   fp = fopen (name, mode);
794   if (!fp)
795     {
796       log_error ("can't open `%s' in \"%s\" mode: %s\n",
797                  name, mode, strerror (errno));
798       return;
799     }
800   fd = fileno (fp);
801
802   if (opt.verbose)
803     log_error ("file `%s' opened in \"%s\" mode, fd=%d\n",
804                name, mode, fd);
805
806   rc = assuan_sendfd (ctx, INT2FD (fd) );
807   if (rc)
808     log_error ("sending descriptor %d failed: %s\n", fd, gpg_strerror (rc));
809   fclose (fp);
810 }
811
812
813 static void
814 do_recvfd (assuan_context_t ctx, char *line)
815 {
816   log_info ("This command has not yet been implemented\n");
817 }
818
819
820 static void
821 do_open (char *line)
822 {
823   FILE *fp;
824   char *varname, *name, *mode, *p;
825   int fd;
826
827 #ifdef HAVE_W32_SYSTEM
828   if (server_pid == (pid_t)(-1))
829     {
830       log_error ("the pid of the server is unknown\n");
831       log_info ("use command \"/serverpid\" first\n");
832       return;
833     }
834 #endif
835
836   /* Get variable name. */
837   varname = line;
838   for (p=varname; *p && !spacep (p); p++)
839     ;
840   if (*p)
841     *p++ = 0;
842   while (spacep (p))
843     p++;
844
845   /* Get file name. */
846   name = p;
847   for (p=name; *p && !spacep (p); p++)
848     ;
849   if (*p)
850     *p++ = 0;
851   while (spacep (p))
852     p++;
853
854   /* Get mode.  */
855   mode = p;
856   if (!*mode)
857     mode = "r";
858   else
859     {
860       for (p=mode; *p && !spacep (p); p++)
861         ;
862       if (*p)
863         *p++ = 0;
864     }
865
866   /* Open and send. */
867   fp = fopen (name, mode);
868   if (!fp)
869     {
870       log_error ("can't open `%s' in \"%s\" mode: %s\n",
871                  name, mode, strerror (errno));
872       return;
873     }
874   fd = fileno (fp);
875   if (fd >= 0 && fd < DIM (open_fd_table))
876     {
877       open_fd_table[fd].inuse = 1;
878 #ifdef HAVE_W32_SYSTEM
879       {
880         HANDLE prochandle, handle, newhandle;
881
882         handle = (void*)_get_osfhandle (fd);
883      
884         prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid);
885         if (!prochandle)
886           {
887             log_error ("failed to open the server process\n");
888             close (fd);
889             return;
890           }
891
892         if (!DuplicateHandle (GetCurrentProcess(), handle,
893                               prochandle, &newhandle, 0,
894                               TRUE, DUPLICATE_SAME_ACCESS ))
895           {
896             log_error ("failed to duplicate the handle\n");
897             close (fd);
898             CloseHandle (prochandle);
899             return;
900           }
901         CloseHandle (prochandle);
902         open_fd_table[fd].handle = newhandle;
903       }
904       if (opt.verbose)
905         log_info ("file `%s' opened in \"%s\" mode, fd=%d  (libc=%d)\n",
906                    name, mode, (int)open_fd_table[fd].handle, fd);
907       set_int_var (varname, (int)open_fd_table[fd].handle);
908 #else  
909       if (opt.verbose)
910         log_info ("file `%s' opened in \"%s\" mode, fd=%d\n",
911                    name, mode, fd);
912       set_int_var (varname, fd);
913 #endif
914     }
915   else
916     {
917       log_error ("can't put fd %d into table\n", fd);
918       close (fd);
919     }
920 }
921
922
923 static void
924 do_close (char *line)
925 {
926   int fd = atoi (line);
927
928 #ifdef HAVE_W32_SYSTEM
929   int i;
930
931   for (i=0; i < DIM (open_fd_table); i++)
932     if ( open_fd_table[i].inuse && open_fd_table[i].handle == (void*)fd)
933       break;
934   if (i < DIM (open_fd_table))
935     fd = i;
936   else
937     {
938       log_error ("given fd (system handle) has not been opened\n");
939       return;
940     }
941 #endif
942
943   if (fd < 0 || fd >= DIM (open_fd_table))
944     {
945       log_error ("invalid fd\n");
946       return;
947     }
948
949   if (!open_fd_table[fd].inuse)
950     {
951       log_error ("given fd has not been opened\n");
952       return;
953     }
954 #ifdef HAVE_W32_SYSTEM
955   CloseHandle (open_fd_table[fd].handle); /* Close duped handle.  */
956 #endif
957   close (fd);
958   open_fd_table[fd].inuse = 0;
959 }
960
961
962 static void
963 do_showopen (void)
964 {
965   int i;
966
967   for (i=0; i < DIM (open_fd_table); i++)
968     if (open_fd_table[i].inuse)
969       {
970 #ifdef HAVE_W32_SYSTEM
971         printf ("%-15d (libc=%d)\n", (int)open_fd_table[i].handle, i);
972 #else
973         printf ("%-15d\n", i);
974 #endif
975       }
976 }
977
978
979
980 static int
981 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
982 {
983   membuf_t *mb = opaque;
984   put_membuf (mb, buffer, length);
985   return 0;
986 }
987
988 /* Get the pid of the server and store it locally.  */
989 static void
990 do_serverpid (assuan_context_t ctx)
991 {
992   int rc;
993   membuf_t mb;
994   char *buffer;
995   
996   init_membuf (&mb, 100);
997   rc = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, &mb,
998                         NULL, NULL, NULL, NULL);
999   put_membuf (&mb, "", 1);
1000   buffer = get_membuf (&mb, NULL);
1001   if (rc || !buffer)
1002     log_error ("command \"%s\" failed: %s\n", 
1003                "GETINFO pid", gpg_strerror (rc));
1004   else
1005     {
1006       server_pid = (pid_t)strtoul (buffer, NULL, 10);
1007       if (opt.verbose)
1008         log_info ("server's PID is %lu\n", (unsigned long)server_pid);
1009     }
1010   xfree (buffer);
1011 }
1012
1013
1014 /* gpg-connect-agent's entry point. */
1015 int
1016 main (int argc, char **argv)
1017 {
1018   ARGPARSE_ARGS pargs;
1019   int no_more_options = 0;
1020   assuan_context_t ctx;
1021   char *line, *p;
1022   char *tmpline;
1023   size_t linesize;
1024   int rc;
1025   int cmderr;
1026   const char *opt_run = NULL;
1027   FILE *script_fp = NULL;
1028   int use_tty, last_was_tty;
1029
1030
1031   gnupg_rl_initialize ();
1032   set_strusage (my_strusage);
1033   log_set_prefix ("gpg-connect-agent", 1);
1034
1035   /* Make sure that our subsystems are ready.  */
1036   init_common_subsystems ();
1037
1038   assuan_set_assuan_err_source (0);
1039
1040   i18n_init();
1041
1042   opt.homedir = default_homedir ();
1043   opt.connect_flags = 1; /* Use extended connect mode.  */
1044
1045   /* Parse the command line. */
1046   pargs.argc  = &argc;
1047   pargs.argv  = &argv;
1048   pargs.flags =  1;  /* Do not remove the args.  */
1049   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
1050     {
1051       switch (pargs.r_opt)
1052         {
1053         case oQuiet:     opt.quiet = 1; break;
1054         case oVerbose:   opt.verbose++; break;
1055         case oNoVerbose: opt.verbose = 0; break;
1056         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
1057         case oHex:       opt.hex = 1; break;
1058         case oDecode:    opt.decode = 1; break;
1059         case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
1060         case oExec:      opt.exec = 1; break;
1061         case oNoExtConnect: opt.connect_flags &= ~(1); break;
1062         case oRun:       opt_run = pargs.r.ret_str; break;
1063         case oSubst:     opt.enable_varsubst = 1; break;
1064
1065         default: pargs.err = 2; break;
1066         }
1067     }
1068
1069   if (log_get_errorcount (0))
1070     exit (2);
1071
1072   use_tty = (isatty ( fileno (stdin)) && isatty (fileno (stdout)));
1073
1074   if (opt.exec)
1075     {
1076       if (!argc)
1077         {
1078           log_error (_("option \"%s\" requires a program "
1079                        "and optional arguments\n"), "--exec" );
1080           exit (1);
1081         }
1082     }
1083   else if (argc)
1084     usage (1);
1085
1086   if (opt.exec && opt.raw_socket)
1087     log_info (_("option \"%s\" ignored due to \"%s\"\n"),
1088               "--raw-socket", "--exec");
1089
1090   if (opt_run && !(script_fp = fopen (opt_run, "r")))
1091     {
1092       log_error ("cannot open run file `%s': %s\n",
1093                  opt_run, strerror (errno));
1094       exit (1);
1095     }
1096
1097
1098   if (opt.exec)
1099     {
1100       int no_close[3];
1101
1102       no_close[0] = fileno (stderr);
1103       no_close[1] = log_get_fd ();
1104       no_close[2] = -1;
1105       rc = assuan_pipe_connect_ext (&ctx, *argv, (const char **)argv,
1106                                     no_close, NULL, NULL,
1107                                     opt.connect_flags);
1108       if (rc)
1109         {
1110           log_error ("assuan_pipe_connect_ext failed: %s\n",
1111                      gpg_strerror (rc));
1112           exit (1);
1113         }
1114
1115       if (opt.verbose)
1116         log_info ("server `%s' started\n", *argv);
1117
1118     }
1119   else if (opt.raw_socket)
1120     {
1121       rc = assuan_socket_connect_ext (&ctx, opt.raw_socket, 0,
1122                                       opt.connect_flags);
1123       if (rc)
1124         {
1125           log_error ("can't connect to socket `%s': %s\n",
1126                      opt.raw_socket, gpg_strerror (rc));
1127           exit (1);
1128         }
1129
1130       if (opt.verbose)
1131         log_info ("connection to socket `%s' established\n", opt.raw_socket);
1132     }
1133   else
1134     ctx = start_agent ();
1135
1136   /* See whether there is a line pending from the server (in case
1137      assuan did not run the initial handshaking).  */
1138   if (assuan_pending_line (ctx))
1139     {
1140       rc = read_and_print_response (ctx, &cmderr);
1141       if (rc)
1142         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1143     }
1144
1145  
1146   line = NULL;
1147   linesize = 0;
1148   last_was_tty = 0;
1149   for (;;)
1150     {
1151       int n;
1152       size_t maxlength;
1153
1154       maxlength = 2048;
1155       if (use_tty && !script_fp)
1156         {
1157           last_was_tty = 1;
1158           line = tty_get ("> ");
1159           n = strlen (line);
1160           if (n==1 && *line == CONTROL_D)
1161             n = 0;
1162           if (n >= maxlength)
1163             maxlength = 0;
1164         }
1165       else
1166         {
1167           if (last_was_tty)
1168             {
1169               xfree (line);
1170               line = NULL;
1171               linesize = 0;
1172               last_was_tty = 0;
1173             }
1174           n = read_line (script_fp? script_fp:stdin, 
1175                          &line, &linesize, &maxlength);
1176         }
1177       if (n < 0)
1178         {
1179           log_error (_("error reading input: %s\n"), strerror (errno));
1180           if (script_fp)
1181             {
1182               fclose (script_fp);
1183               script_fp = NULL;
1184               log_error ("stopping script execution\n");
1185               continue;
1186             }
1187           exit (1);
1188         }
1189       if (!n)
1190         {
1191           /* EOF */
1192           if (script_fp)
1193             {
1194               fclose (script_fp);
1195               script_fp = NULL;
1196               if (opt.verbose)
1197                 log_info ("end of script\n");
1198               continue;
1199             }
1200           break; 
1201         }
1202       if (!maxlength)
1203         {
1204           log_error (_("line too long - skipped\n"));
1205           continue;
1206         }
1207       if (memchr (line, 0, n))
1208         log_info (_("line shortened due to embedded Nul character\n"));
1209       if (line[n-1] == '\n')
1210         line[n-1] = 0;
1211       if (*line == '/')
1212         {
1213           /* Handle control commands. */
1214           char *cmd = line+1;
1215
1216           for (p=cmd; *p && !spacep (p); p++)
1217             ;
1218           if (*p)
1219             *p++ = 0;
1220           while (spacep (p))
1221             p++;
1222           if (!strcmp (cmd, "let"))
1223             {
1224               assign_variable (p, 0);
1225             }
1226           else if (!strcmp (cmd, "slet"))
1227             {
1228               /* Deprecated - never used in a released version.  */
1229               assign_variable (p, 1);
1230             }
1231           else if (!strcmp (cmd, "showvar"))
1232             {
1233               show_variables ();
1234             }
1235           else if (!strcmp (cmd, "definq"))
1236             {
1237               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1238               if (tmpline)
1239                 {
1240                   add_definq (tmpline, 1, 0);
1241                   xfree (tmpline);
1242                 }
1243               else
1244                 add_definq (p, 1, 0);
1245             }
1246           else if (!strcmp (cmd, "definqfile"))
1247             {
1248               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1249               if (tmpline)
1250                 {
1251                   add_definq (tmpline, 0, 0);
1252                   xfree (tmpline);
1253                 }
1254               else
1255                 add_definq (p, 0, 0);
1256             }
1257           else if (!strcmp (cmd, "definqprog"))
1258             {
1259               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1260               if (tmpline)
1261                 {
1262                   add_definq (tmpline, 0, 1);
1263                   xfree (tmpline);
1264                 }
1265               else
1266                 add_definq (p, 0, 1);
1267             }
1268           else if (!strcmp (cmd, "showdef"))
1269             {
1270               show_definq ();
1271             }
1272           else if (!strcmp (cmd, "cleardef"))
1273             {
1274               clear_definq ();
1275             }
1276           else if (!strcmp (cmd, "echo"))
1277             {
1278               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1279               if (tmpline)
1280                 {
1281                   puts (tmpline);
1282                   xfree (tmpline);
1283                 }
1284               else
1285                 puts (p);
1286             }
1287           else if (!strcmp (cmd, "sendfd"))
1288             {
1289               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1290               if (tmpline)
1291                 {
1292                   do_sendfd (ctx, tmpline);
1293                   xfree (tmpline);
1294                 }
1295               else
1296                 do_sendfd (ctx, p);
1297               continue;
1298             }
1299           else if (!strcmp (cmd, "recvfd"))
1300             {
1301               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1302               if (tmpline)
1303                 {
1304                   do_recvfd (ctx, tmpline);
1305                   xfree (tmpline);
1306                 }
1307               else
1308                 do_recvfd (ctx, p);
1309               continue;
1310             }
1311           else if (!strcmp (cmd, "open"))
1312             {
1313               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1314               if (tmpline)
1315                 {
1316                   do_open (tmpline);
1317                   xfree (tmpline);
1318                 }
1319               else
1320                 do_open (p);
1321             }
1322           else if (!strcmp (cmd, "close"))
1323             {
1324               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1325               if (tmpline)
1326                 {
1327                   do_close (tmpline);
1328                   xfree (tmpline);
1329                 }
1330               else
1331                 do_close (p);
1332             }
1333           else if (!strcmp (cmd, "showopen"))
1334             {
1335               do_showopen ();
1336             }
1337           else if (!strcmp (cmd, "serverpid"))
1338             {
1339               do_serverpid (ctx);
1340             }
1341           else if (!strcmp (cmd, "hex"))
1342             opt.hex = 1;
1343           else if (!strcmp (cmd, "nohex"))
1344             opt.hex = 0;
1345           else if (!strcmp (cmd, "decode"))
1346             opt.decode = 1;
1347           else if (!strcmp (cmd, "nodecode"))
1348             opt.decode = 0;
1349           else if (!strcmp (cmd, "subst"))
1350             opt.enable_varsubst = 1;
1351           else if (!strcmp (cmd, "nosubst"))
1352             opt.enable_varsubst = 0;
1353           else if (!strcmp (cmd, "run"))
1354             {
1355               char *p2;
1356               for (p2=p; *p2 && !spacep (p2); p2++)
1357                 ;
1358               if (*p2)
1359                 *p2++ = 0;
1360               while (spacep (p2))
1361                 p++;
1362               if (*p2)
1363                 {
1364                   log_error ("syntax error in run command\n");
1365                   if (script_fp)
1366                     {
1367                       fclose (script_fp);
1368                       script_fp = NULL;
1369                     }
1370                 }
1371               else if (script_fp)
1372                 {
1373                   log_error ("cannot nest run commands - stop\n");
1374                   fclose (script_fp);
1375                   script_fp = NULL;
1376                 }
1377               else if (!(script_fp = fopen (p, "r")))
1378                 {
1379                   log_error ("cannot open run file `%s': %s\n",
1380                              p, strerror (errno));
1381                 }
1382               else if (opt.verbose)
1383                 log_info ("running commands from `%s'\n", p);
1384             }
1385           else if (!strcmp (cmd, "bye"))
1386             {
1387               break;
1388             }
1389           else if (!strcmp (cmd, "help"))
1390             {
1391               puts (
1392 "Available commands:\n"
1393 "/echo ARGS             Echo ARGS.\n"
1394 "/let  NAME VALUE       Set variable NAME to VALUE.\n"
1395 "/showvar               Show all variables.\n"
1396 "/definq NAME VAR       Use content of VAR for inquiries with NAME.\n"
1397 "/definqfile NAME FILE  Use content of FILE for inquiries with NAME.\n"
1398 "/definqprog NAME PGM   Run PGM for inquiries with NAME.\n"
1399 "/showdef               Print all definitions.\n"
1400 "/cleardef              Delete all definitions.\n"
1401 "/sendfd FILE MODE      Open FILE and pass descriptor to server.\n"
1402 "/recvfd                Receive FD from server and print.\n"
1403 "/open VAR FILE MODE    Open FILE and assign the file descriptor to VAR.\n" 
1404 "/close FD              Close file with descriptor FD.\n"
1405 "/showopen              Show descriptors of all open files.\n"
1406 "/serverpid             Retrieve the pid of the server.\n"
1407 "/[no]hex               Enable hex dumping of received data lines.\n"
1408 "/[no]decode            Enable decoding of received data lines.\n"
1409 "/[no]subst             Enable varibale substitution.\n"
1410 "/run FILE              Run commands from FILE.\n"
1411 "/bye                   Terminate gpg-connect-agent.\n"
1412 "/help                  Print this help.");
1413             }
1414           else
1415             log_error (_("unknown command `%s'\n"), cmd );
1416       
1417           continue;
1418         }
1419
1420       if (opt.verbose && script_fp)
1421         puts (line);
1422
1423       tmpline = opt.enable_varsubst? substitute_line (line) : NULL;
1424       if (tmpline)
1425         {
1426           rc = assuan_write_line (ctx, tmpline);
1427           xfree (tmpline);
1428         }
1429       else
1430         rc = assuan_write_line (ctx, line);
1431       if (rc)
1432         {
1433           log_info (_("sending line failed: %s\n"), gpg_strerror (rc) );
1434           break;
1435         }
1436       if (*line == '#' || !*line)
1437         continue; /* Don't expect a response for a comment line. */
1438
1439       rc = read_and_print_response (ctx, &cmderr);
1440       if (rc)
1441         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1442       if ((rc || cmderr) && script_fp)
1443         {
1444           log_error ("stopping script execution\n");
1445           fclose (script_fp);
1446           script_fp = NULL;
1447         }
1448           
1449
1450       /* FIXME: If the last command was BYE or the server died for
1451          some other reason, we won't notice until we get the next
1452          input command.  Probing the connection with a non-blocking
1453          read could help to notice termination or other problems
1454          early.  */
1455     }
1456
1457   if (opt.verbose)
1458     log_info ("closing connection to agent\n");
1459   
1460   return 0; 
1461 }
1462
1463
1464 /* Handle an Inquire from the server.  Return False if it could not be
1465    handled; in this case the caller shll complete the operation.  LINE
1466    is the complete line as received from the server.  This function
1467    may change the content of LINE. */
1468 static int
1469 handle_inquire (assuan_context_t ctx, char *line)
1470 {
1471   const char *name;
1472   definq_t d;
1473   FILE *fp = NULL;
1474   char buffer[1024];
1475   int rc, n;
1476
1477   /* Skip the command and trailing spaces. */
1478   for (; *line && !spacep (line); line++)
1479     ;
1480   while (spacep (line))
1481     line++;
1482   /* Get the name. */
1483   name = line;
1484   for (; *line && !spacep (line); line++)
1485     ;
1486   if (*line)
1487     *line++ = 0;
1488
1489   /* Now match it against our list. he second loop is todetect the
1490      match all entry. **/
1491   for (d=definq_list; d; d = d->next)
1492     if (d->name && !strcmp (d->name, name))
1493         break;
1494   if (!d)
1495     for (d=definq_list; d; d = d->next)
1496       if (!d->name)
1497         break;
1498   if (!d)
1499     {
1500       if (opt.verbose)
1501         log_info ("no handler for inquiry `%s' found\n", name);
1502       return 0;
1503     }
1504
1505   if (d->is_var)
1506     {
1507       char *tmpvalue = get_var_ext (d->file);
1508       rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue));
1509       xfree (tmpvalue);
1510       if (rc)
1511         log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1512     }
1513   else
1514     {
1515       if (d->is_prog)
1516         {
1517           fp = popen (d->file, "r");
1518           if (!fp)
1519             log_error ("error executing `%s': %s\n",
1520                        d->file, strerror (errno));
1521           else if (opt.verbose)
1522             log_error ("handling inquiry `%s' by running `%s'\n", 
1523                        name, d->file);
1524         }
1525       else
1526         {
1527           fp = fopen (d->file, "rb");
1528           if (!fp)
1529             log_error ("error opening `%s': %s\n", d->file, strerror (errno));
1530           else if (opt.verbose)
1531             log_error ("handling inquiry `%s' by returning content of `%s'\n",
1532                        name, d->file);
1533         }
1534       if (!fp)
1535         return 0;
1536
1537       while ( (n = fread (buffer, 1, sizeof buffer, fp)) )
1538         {
1539           rc = assuan_send_data (ctx, buffer, n);
1540           if (rc)
1541             {
1542               log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1543               break;
1544             }
1545         }
1546       if (ferror (fp))
1547         log_error ("error reading from `%s': %s\n", d->file, strerror (errno));
1548     }
1549
1550   rc = assuan_send_data (ctx, NULL, 0);
1551   if (rc)
1552     log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1553
1554   if (d->is_var)
1555     ;
1556   else if (d->is_prog)
1557     {
1558       if (pclose (fp))
1559         log_error ("error running `%s': %s\n", d->file, strerror (errno));
1560     }
1561   else
1562     fclose (fp);
1563   return 1;
1564 }
1565
1566
1567 /* Read all response lines from server and print them.  Returns 0 on
1568    success or an assuan error code.  Set R_GOTERR to true if the
1569    command did not returned OK.  */
1570 static int
1571 read_and_print_response (assuan_context_t ctx, int *r_goterr)
1572 {
1573   char *line;
1574   size_t linelen;
1575   assuan_error_t rc;
1576   int i, j;
1577   int need_lf = 0;
1578
1579   *r_goterr = 0;
1580   for (;;)
1581     {
1582       do 
1583         {
1584           rc = assuan_read_line (ctx, &line, &linelen);
1585           if (rc)
1586             return rc;
1587
1588           if (opt.verbose > 1 && *line == '#')
1589             {
1590               fwrite (line, linelen, 1, stdout);
1591               putchar ('\n');
1592             }
1593         }    
1594       while (*line == '#' || !linelen);
1595
1596       if (linelen >= 1
1597           && line[0] == 'D' && line[1] == ' ')
1598         {
1599           if (opt.hex)
1600             {
1601               for (i=2; i < linelen; )
1602                 {
1603                   int save_i = i;
1604
1605                   printf ("D[%04X] ", i-2);
1606                   for (j=0; j < 16 ; j++, i++)
1607                     {
1608                       if (j == 8)
1609                         putchar (' ');
1610                       if (i < linelen)
1611                         printf (" %02X", ((unsigned char*)line)[i]);
1612                       else
1613                         fputs ("   ", stdout);
1614                     }
1615                   fputs ("   ", stdout);
1616                   i= save_i;
1617                   for (j=0; j < 16; j++, i++)
1618                     {
1619                       unsigned int c = ((unsigned char*)line)[i];
1620                       if ( i >= linelen )
1621                         putchar (' ');
1622                       else if (isascii (c) && isprint (c) && !iscntrl (c))
1623                         putchar (c);
1624                       else
1625                         putchar ('.');
1626                     }
1627                   putchar ('\n');
1628                 }
1629             }
1630           else if (opt.decode)
1631             {
1632               const unsigned char *s;
1633               int need_d = 1;
1634               int c = 0;
1635
1636               for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
1637                 {
1638                   if (need_d)
1639                     {
1640                       fputs ("D ", stdout);
1641                       need_d = 0;
1642                     }
1643                   if (*s == '%' && j+2 < linelen)
1644                     { 
1645                       s++; j++;
1646                       c = xtoi_2 ( s );
1647                       s++; j++;
1648                     }
1649                   else
1650                     c = *s;
1651                   if (c == '\n')
1652                     need_d = 1;
1653                   putchar (c);
1654                 }
1655               need_lf = (c != '\n');
1656             }
1657           else
1658             {
1659               fwrite (line, linelen, 1, stdout);
1660               putchar ('\n');
1661             }
1662         }
1663       else 
1664         {
1665           if (need_lf)
1666             {
1667               putchar ('\n');
1668               need_lf = 0;
1669             }
1670
1671           if (linelen >= 1
1672               && line[0] == 'S' 
1673               && (line[1] == '\0' || line[1] == ' '))
1674             {
1675               fwrite (line, linelen, 1, stdout);
1676               putchar ('\n');
1677             }  
1678           else if (linelen >= 2
1679                    && line[0] == 'O' && line[1] == 'K'
1680                    && (line[2] == '\0' || line[2] == ' '))
1681             {
1682               fwrite (line, linelen, 1, stdout);
1683               putchar ('\n');
1684               return 0;
1685             }
1686           else if (linelen >= 3
1687                    && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
1688                    && (line[3] == '\0' || line[3] == ' '))
1689             {
1690               fwrite (line, linelen, 1, stdout);
1691               putchar ('\n');
1692               *r_goterr = 1;
1693               return 0;
1694             }  
1695           else if (linelen >= 7
1696                    && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1697                    && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1698                    && line[6] == 'E' 
1699                    && (line[7] == '\0' || line[7] == ' '))
1700             {
1701               fwrite (line, linelen, 1, stdout);
1702               putchar ('\n');
1703               if (!handle_inquire (ctx, line))
1704                 assuan_write_line (ctx, "CANCEL");
1705             }
1706           else if (linelen >= 3
1707                    && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
1708                    && (line[3] == '\0' || line[3] == ' '))
1709             {
1710               fwrite (line, linelen, 1, stdout);
1711               putchar ('\n');
1712               /* Received from server, thus more responses are expected.  */
1713             }
1714           else
1715             return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
1716         }
1717     }
1718 }
1719
1720
1721
1722
1723 /* Connect to the agent and send the standard options.  */
1724 static assuan_context_t
1725 start_agent (void)
1726 {
1727   int rc = 0;
1728   char *infostr, *p;
1729   assuan_context_t ctx;
1730
1731   infostr = getenv ("GPG_AGENT_INFO");
1732   if (!infostr || !*infostr)
1733     {
1734       char *sockname;
1735
1736       /* Check whether we can connect at the standard socket.  */
1737       sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
1738       rc = assuan_socket_connect (&ctx, sockname, 0);
1739       xfree (sockname);
1740     }
1741   else
1742     {
1743       int prot;
1744       int pid;
1745
1746       infostr = xstrdup (infostr);
1747       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
1748         {
1749           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
1750           xfree (infostr);
1751           exit (1);
1752         }
1753       *p++ = 0;
1754       pid = atoi (p);
1755       while (*p && *p != PATHSEP_C)
1756         p++;
1757       prot = *p? atoi (p+1) : 0;
1758       if (prot != 1)
1759         {
1760           log_error (_("gpg-agent protocol version %d is not supported\n"),
1761                      prot);
1762           xfree (infostr);
1763           exit (1);
1764         }
1765
1766       rc = assuan_socket_connect (&ctx, infostr, pid);
1767       xfree (infostr);
1768     }
1769
1770   if (rc)
1771     {
1772       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
1773       exit (1);
1774     }
1775
1776   if (opt.verbose)
1777     log_info ("connection to agent established\n");
1778
1779   rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1780   if (rc)
1781     {
1782       log_error (_("error sending %s command: %s\n"), "RESET", 
1783                  gpg_strerror (rc));
1784       exit (1);
1785     }
1786
1787   rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
1788                                   NULL, NULL, NULL, NULL, NULL);
1789   if (rc)
1790     {
1791       log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
1792       exit (1);
1793     }
1794
1795   return ctx;
1796 }