2003-05-18 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / passphrase.c
1 /* passphrase.c - Passphrase callback.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gpgme.h"
29 #include "context.h"
30 #include "ops.h"
31
32 \f
33 typedef struct
34 {
35   int no_passphrase;
36   void *last_pw_handle;
37   char *userid_hint;
38   char *passphrase_info;
39   int bad_passphrase;
40 } *op_data_t;
41
42
43 static void
44 release_op_data (void *hook)
45 {
46   op_data_t opd = (op_data_t) hook;
47
48   free (opd->passphrase_info);
49   free (opd->userid_hint);
50 }
51
52 \f
53 gpgme_error_t
54 _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, char *args)
55 {
56   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
57   gpgme_error_t err;
58   op_data_t opd;
59
60   if (!ctx->passphrase_cb)
61     return 0;
62
63   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, (void **) &opd,
64                                sizeof (*opd), release_op_data);
65   if (err)
66     return err;
67
68   switch (code)
69     {
70     case GPGME_STATUS_USERID_HINT:
71       if (opd->userid_hint)
72         free (opd->userid_hint);
73       if (!(opd->userid_hint = strdup (args)))
74         return GPGME_Out_Of_Core;
75       break;
76
77     case GPGME_STATUS_BAD_PASSPHRASE:
78       opd->bad_passphrase++;
79       opd->no_passphrase = 0;
80       break;
81
82     case GPGME_STATUS_GOOD_PASSPHRASE:
83       opd->bad_passphrase = 0;
84       opd->no_passphrase = 0;
85       break;
86
87     case GPGME_STATUS_NEED_PASSPHRASE:
88     case GPGME_STATUS_NEED_PASSPHRASE_SYM:
89       if (opd->passphrase_info)
90         free (opd->passphrase_info);
91       opd->passphrase_info = strdup (args);
92       if (!opd->passphrase_info)
93         return GPGME_Out_Of_Core;
94       break;
95
96     case GPGME_STATUS_MISSING_PASSPHRASE:
97       opd->no_passphrase = 1;
98       break;
99
100     case GPGME_STATUS_EOF:
101       if (opd->no_passphrase || opd->bad_passphrase)
102         return GPGME_Bad_Passphrase;
103       break;
104
105     default:
106       /* Ignore all other codes.  */
107       break;
108     }
109   return 0;
110 }
111
112
113 gpgme_error_t
114 _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
115                                    const char *key, const char **result)
116 {
117   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
118   gpgme_error_t err;
119   op_data_t opd;
120
121   if (!ctx->passphrase_cb)
122     return 0;
123
124   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, (void **) &opd,
125                                sizeof (*opd), release_op_data);
126   if (err)
127     return err;
128
129   if (!code)
130     {
131       /* We have been called for cleanup.  */
132       if (ctx->passphrase_cb)
133         /* FIXME: Take the key in account.  */
134         err = ctx->passphrase_cb (ctx->passphrase_cb_value, NULL,
135                                   &opd->last_pw_handle, NULL);
136       *result = NULL;
137       return err;
138     }
139
140   if (!key || !ctx->passphrase_cb)
141     {
142       *result = NULL;
143       return 0;
144     }
145     
146   if (code == GPGME_STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter"))
147     {
148       const char *userid_hint = opd->userid_hint;
149       const char *passphrase_info = opd->passphrase_info;
150       int bad_passphrase = opd->bad_passphrase;
151       char *buf;
152
153       opd->bad_passphrase = 0;
154       if (!userid_hint)
155         userid_hint = "[User ID hint missing]";
156       if (!passphrase_info)
157         passphrase_info = "[passphrase info missing]";
158       buf = malloc (20 + strlen (userid_hint)
159                     + strlen (passphrase_info) + 3);
160       if (!buf)
161         return GPGME_Out_Of_Core;
162       sprintf (buf, "%s\n%s\n%s",
163                bad_passphrase ? "TRY_AGAIN":"ENTER",
164                userid_hint, passphrase_info);
165
166       err = ctx->passphrase_cb (ctx->passphrase_cb_value, buf,
167                                 &opd->last_pw_handle, result);
168       free (buf);
169       return err;
170     }
171
172   *result = NULL;
173   return 0;
174 }