/[winpt]/trunk/Src/wptKeyEdit.cpp
ViewVC logotype

Annotation of /trunk/Src/wptKeyEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 17 08:49:30 2005 UTC (19 years, 4 months ago) by twoaday
File size: 18223 byte(s)
More bug fixes all over the place.
See ChangeLog for details.

1 twoaday 23 /* wptKeyEdit.cpp - GPG key edit abstraction
2     * Copyright (C) 2005 Timo Schulz
3 twoaday 24 * Copyright (C) 2005 g10 Code GmbH
4 twoaday 23 *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *
12     * WinPT is distributed in the hope that it will be useful,
13     * but 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 WinPT; if not, write to the Free Software Foundation,
19     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     #include <windows.h>
23    
24 twoaday 25 #include "gpgme.h"
25 twoaday 23 #include "wptCommonCtl.h"
26     #include "wptContext.h"
27     #include "wptKeyEdit.h"
28     #include "wptTypes.h"
29     #include "wptW32API.h"
30     #include "wptGPG.h"
31 twoaday 24 #include "wptErrors.h"
32 twoaday 23
33 twoaday 25
34 twoaday 23 /* Parse the colon status information of @line and store
35     the information in @rev.
36     Return value: 0 on success. */
37     static gpgme_error_t
38     rev_key_colon_handler (gpg_desig_rev_t *rev, char *line)
39     {
40     char *p, *pend;
41     gpg_desig_rev_t r, t;
42     int field = 0;
43    
44 twoaday 24 if (!line || strlen (line) < 3)
45 twoaday 23 return gpg_error (GPG_ERR_EOF);
46 twoaday 24 if (strncmp (line, "rvk", 3))
47     return 0; /* skip this line. */
48 twoaday 23
49 twoaday 24 log_debug ("rev_key: line=%s\r\n", line);
50    
51 twoaday 23 r = (gpg_desig_rev_t)calloc (1, sizeof *r);
52     if (!r)
53     return gpg_error (GPG_ERR_ENOMEM);
54     if (!*rev)
55     *rev = r;
56     else {
57     for (t=*rev; t->next; t=t->next)
58     ;
59     t->next = r;
60     }
61    
62     p = strdup (line);
63     if (!p)
64     return gpg_error (GPG_ERR_ENOMEM);
65    
66     for (;;) {
67     field++;
68     pend = strsep (&p, ":");
69     if (pend == NULL)
70     break;
71     switch (field) {
72 twoaday 25 case 4: r->pubkey_algo = (gpgme_pubkey_algo_t)atol (pend); break;
73 twoaday 24 case 10: strncpy (r->fpr, pend, 40); r->fpr[40] = 0; break;
74     }
75 twoaday 23 }
76     if (p)
77     free (p);
78     return 0;
79     }
80    
81    
82     /* Parse the colon data output of edit key from @line and
83     store the information in the @inf context.
84     Return value: 0 on success. */
85     static gpgme_error_t
86     uid_inf_colon_handler (gpg_uid_info_t *inf, char *line)
87     {
88 twoaday 25 gpg_uid_info_t i, t;
89 twoaday 23 char *p, *pend;
90     int field = 0, len = 0;
91    
92     if (!line || strlen (line) < 3 || strncmp (line, "uid", 3))
93     return gpg_error (GPG_ERR_EOF);
94    
95     i = (gpg_uid_info_t)calloc (1, sizeof *i);
96     if (!i)
97     return gpg_error (GPG_ERR_ENOMEM);
98     if (!*inf)
99     *inf = i;
100     else {
101     for (t=*inf; t->next; t=t->next)
102     ;
103     t->next = i;
104     }
105    
106     p = strdup (line);
107     if (!p)
108     return gpg_error (GPG_ERR_ENOMEM);;
109     for (;;) {
110     field++;
111     pend = strsep (&p, ":");
112     if (pend == NULL)
113     break;
114    
115     switch (field) {
116     case 2: /* trust info */
117     break;
118    
119     case 10: /* user ID */
120     i->name = (char *)calloc (1, strlen (pend)+1);
121     if (!i->name)
122     return gpg_error (GPG_ERR_ENOMEM);;
123 twoaday 24 gpg_decode_c_string (pend, &i->name, strlen (pend)+ 1);
124 twoaday 23 if (strchr (pend, '<') != NULL && strchr (pend, '>') != NULL) {
125     int pos = strchr (i->name, '<')- i->name + 1;
126     int end = strchr (i->name, '>') - i->name;
127     i->email = (char*) calloc (1, end-pos+2);
128     if (!i->email)
129     return gpg_error (GPG_ERR_ENOMEM);;
130     memcpy (i->email, i->name+pos, (end-pos));
131     }
132     break;
133    
134     case 13: /* preferences */
135     if (strstr (pend, "mdc")) {
136     len = strlen (pend) - 4; /* ,mdc */
137     if (strstr (pend, "no-ks-modify")) {
138     i->flags.no_ks_modify = 1;
139     len -= 13; /* ,no-ks-modify */
140     }
141     i->prefs = (char*)calloc (1, len+1);
142     if (!i->prefs)
143     return gpg_error (GPG_ERR_ENOMEM);
144     memcpy (i->prefs, pend, len);
145     i->prefs[len] = '\0';
146     i->flags.mdc = 1;
147     }
148     else {
149     i->prefs = strdup (pend);
150     if (!i->prefs)
151     return gpg_error (GPG_ERR_ENOMEM);
152     i->flags.mdc = 0;
153     }
154     break;
155    
156     case 14: /* index/flags */
157     i->index = atol (pend);
158     if (strchr (pend, 'r'))
159     i->flags.revoked = 1;
160     if (strchr (pend, 'p'))
161     i->flags.primary = 1;
162     break;
163     }
164     }
165     if (p)
166     free (p);
167     return 0;
168     }
169    
170    
171     /* Release the context in @inf. */
172     void
173     gpg_uid_info_release (gpg_uid_info_t list)
174     {
175     gpg_uid_info_t i;
176    
177     while (list) {
178     i = list->next;
179     if (list->name) {
180     if (list->name)
181     free (list->name);
182     list->name = NULL;
183     }
184     if (list->prefs) {
185     if (list->prefs)
186     free (list->prefs);
187     list->prefs = NULL;
188     }
189     free (list);
190     list = i;
191     }
192     }
193    
194    
195     /* Release the context in @rev. */
196     void
197     gpg_desig_rev_release (gpg_desig_rev_t rev)
198     {
199     gpg_desig_rev_t r;
200    
201     while (rev) {
202     r = rev->next;
203     free (rev);
204     rev = r;
205     }
206     }
207    
208    
209 twoaday 25 static gpgme_error_t
210     list2_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
211     {
212     DWORD n;
213     const char *s;
214    
215     if (!strcmp (key, "keyedit.prompt")) {
216     s = "quit\n";
217     WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
218     }
219     return 0;
220     }
221    
222 twoaday 24 /* Dummy handler to get the colon data and then quit. */
223     static gpgme_error_t
224     list_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
225     {
226     static int step=0;
227     const char *s="";
228     DWORD n;
229    
230     if (!strcmp (key, "keyedit.prompt") && step == 0) {
231     step = 1;
232     s = "list\n";
233     WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
234     }
235     else if (!strcmp (key, "keyedit.prompt") && step == 1) {
236     step = 0;
237     s = "quit\n";
238     WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
239     }
240 twoaday 25
241 twoaday 24 return 0;
242     }
243    
244    
245 twoaday 23 /* Return all designated revokers for this key. If no revoker
246     was set, @r_rev is NULL.
247     Return value: 0 on success. */
248     gpgme_error_t
249     GpgKeyEdit::getDesignatedRevoker (gpg_desig_rev_t *r_rev)
250     {
251     gpgme_data_t out=NULL;
252     gpg_desig_rev_t rev = NULL;
253     gpgme_error_t err;
254 twoaday 25 char buf[256];
255 twoaday 23
256     if (!this->key)
257     return gpg_error (GPG_ERR_INV_OBJ);
258    
259     err = gpgme_data_new (&out);
260     if (err)
261     goto leave;
262    
263 twoaday 25 err = gpgme_op_edit (ctx, key, list2_handler, NULL, out);
264 twoaday 23 if (err)
265     goto leave;
266 twoaday 24
267     gpgme_data_rewind (out);
268 twoaday 25 while (gpg_data_readline (out, buf, sizeof (buf)-1) > 0)
269 twoaday 23 rev_key_colon_handler (&rev, buf);
270 twoaday 25 *r_rev = rev;
271 twoaday 23
272     leave:
273     if (out)
274     gpgme_data_release (out);
275     if (err) {
276     gpg_desig_rev_release (rev);
277     *r_rev = NULL;
278     }
279     return err;
280     }
281    
282     /* Retrieve all user ID information of the key set via setKey
283     in @r_inf. The result also contains the user ID number which
284     is needed to securely delete the user-ID. */
285     gpgme_error_t
286     GpgKeyEdit::getUseridInfo (gpg_uid_info_t *r_uinf)
287     {
288     gpgme_data_t out = NULL;
289     gpgme_error_t err;
290     gpg_uid_info_t inf = NULL;
291 twoaday 25 char buf[256];
292 twoaday 23
293     if (!this->key)
294     return gpg_error (GPG_ERR_INV_OBJ);
295    
296     err = gpgme_data_new (&out);
297     if (err)
298     goto leave;
299    
300 twoaday 25 err = gpgme_op_edit (ctx, key, list_handler, NULL, out);
301 twoaday 23 if (err)
302     goto leave;
303    
304 twoaday 25 gpgme_data_rewind (out);
305     while (gpg_data_readline (out, buf, sizeof (buf) -1) > 0)
306 twoaday 23 uid_inf_colon_handler (&inf, buf);
307    
308     *r_uinf = inf;
309    
310     leave:
311     if (out)
312     gpgme_data_release (out);
313     if (err) {
314     gpg_uid_info_release (inf);
315     *r_uinf = NULL;
316     }
317     return err;
318     }
319    
320    
321     /* Construct an object with the given key in @key. */
322     GpgKeyEdit::GpgKeyEdit (gpgme_key_t key)
323     {
324     this->key = key;
325     pass = NULL;
326     type = 0;
327     name = NULL;
328     cmt = NULL;
329     email = NULL;
330 twoaday 24 cnt = 0;
331     cmd_sent = 0;
332     resval = 0;
333 twoaday 23 gpgme_new (&ctx); /* FIXME */
334     }
335    
336     /* Construct an object and fetch the key with the keyid @keyid. */
337     GpgKeyEdit::GpgKeyEdit (const char *keyid)
338     {
339     get_pubkey (keyid, &this->key);
340     pass = NULL;
341     type = 0;
342     name = NULL;
343     cmt = NULL;
344     email = NULL;
345 twoaday 24 cmd_sent = 0;
346     resval = 0;
347 twoaday 23 gpgme_new (&ctx); /* FIXME */
348     }
349    
350     /* Delete the given object. */
351     GpgKeyEdit::~GpgKeyEdit (void)
352     {
353     free_if_alloc (name);
354     free_if_alloc (cmt);
355     free_if_alloc (email);
356     gpgme_release (ctx);
357     }
358    
359    
360 twoaday 24 /* Reset the state of the object. */
361     void
362     GpgKeyEdit::reset (void)
363     {
364     cmd_sent = 0;
365     }
366    
367    
368 twoaday 23 /* Return true if type has a non-zero value. */
369     bool
370     GpgKeyEdit::isValid (void)
371     {
372     return type != 0;
373     }
374    
375    
376     /* Return the GPGME key. */
377     gpgme_key_t
378     GpgKeyEdit::getKey (void)
379     {
380     return key;
381     }
382    
383    
384     /* Set the GPGME callback to @cb. The hook value can be
385     given in @cb_value. */
386     void
387     GpgKeyEdit::setCallback (gpgme_progress_cb_t cb, void *cb_value)
388     {
389     gpgme_set_progress_cb (ctx, cb, cb_value);
390     }
391    
392     /* Set the passphrase to @pass. */
393     void
394     GpgKeyEdit::setPassphrase (const char *pass)
395     {
396     this->pass = pass;
397     }
398    
399     /* Set the current key to @key. */
400     void
401     GpgKeyEdit::setKey (gpgme_key_t key)
402     {
403     this->key = key;
404     }
405    
406 twoaday 24 /* Set the keyid of the destination key to @keyid. */
407 twoaday 23 void
408     GpgKeyEdit::setKeyID (const char *keyid)
409     {
410     if (!keyid)
411     return;
412     get_pubkey (keyid, &this->key);
413     }
414    
415    
416 twoaday 24 /* Set the local user for the operation to @locusr. */
417 twoaday 23 void
418     GpgKeyEdit::setLocalUser (gpgme_key_t locusr)
419     {
420     gpgme_signers_add (ctx, locusr);
421     }
422    
423 twoaday 24 /* Set the result of the operation to @val. */
424     void
425 twoaday 26 GpgKeyEdit::setResult (int val)
426 twoaday 24 {
427     resval |= val;
428     }
429 twoaday 23
430 twoaday 24
431     /* Return the result of the operation. */
432     int
433 twoaday 26 GpgKeyEdit::getResult(void)
434 twoaday 24 {
435     return resval;
436     }
437    
438    
439 twoaday 23 /* Sign the key stored in the object with the
440     signing mode @mode and the signature class @sig_class.
441     Return value: 0 on success. */
442     gpgme_error_t
443     GpgKeyEdit::signKey (int mode, int sig_class, const char *exp_date)
444     {
445     if (!this->key || !this->pass)
446     return gpg_error (GPG_ERR_INV_OBJ);
447    
448     type = mode;
449     this->exp_date = exp_date;
450     this->sig_class = sig_class;
451     return gpg_editkey (this->ctx, this->key, this);
452     }
453    
454     /* Set the ownertrust of the key stored in the object
455     to the trust value @trust.
456     Return value: 0 on success. */
457     gpgme_error_t
458     GpgKeyEdit::setTrust (gpgme_validity_t trust)
459     {
460     if (!this->key)
461     return gpg_error (GPG_ERR_INV_OBJ);
462    
463     type = GPG_EDITKEY_TRUST;
464     this->trust_id = (int)trust;
465     return gpg_editkey (this->ctx, this->key, this);
466     }
467    
468     /* Add a user ID to the given key with the @name as the
469     name, @cmt as the comment (or NULL) and @email as the email.
470     Return value: 0 on success. */
471     gpgme_error_t
472     GpgKeyEdit::addUserid (const char *name, const char *cmt, const char *email)
473     {
474     if (!this->key || !this->pass)
475     return gpg_error (GPG_ERR_INV_OBJ);
476    
477     type = GPG_EDITKEY_ADDUID;
478     free_if_alloc (this->name);
479     this->name = m_strdup (name);
480     free_if_alloc (this->cmt);
481 twoaday 25 this->cmt = NULL;
482     if (cmt != NULL)
483     this->cmt = m_strdup (cmt);
484 twoaday 23 free_if_alloc (this->email);
485     this->email = m_strdup (email);
486 twoaday 25 if (!this->email || !this->name)
487 twoaday 23 BUG (NULL);
488     return gpg_editkey (this->ctx, this->key, this);
489     }
490    
491     /* Delete the user-ID with the index @uid_index of the given key.
492     Return value: 0 on success. */
493     gpgme_error_t
494     GpgKeyEdit::delUserid (int uid_index)
495     {
496     if (!this->key)
497     return gpg_error (GPG_ERR_INV_OBJ);
498    
499     type = GPG_EDITKEY_DELUID;
500     this->uid_index = uid_index;
501     return gpg_editkey (this->ctx, this->key, this);
502     }
503    
504     /* Delete the subkey with the index @key_index.
505     Return value: 0 on success. */
506     gpgme_error_t
507     GpgKeyEdit::delKey (int key_index)
508     {
509     if (!this->key)
510     return gpg_error (GPG_ERR_INV_OBJ);
511    
512     type = GPG_EDITKEY_DELKEY;
513     this->key_index = key_index;
514     return gpg_editkey (this->ctx, this->key, this);
515     }
516    
517     /* Add a new subkey to the given key.
518     The new key will have @pubkey_algo as the algorithm
519     and a size of @pubkey_size bits. If valid > 0, the
520     key expires in @valid days.
521     Return value: 0 on success. */
522     gpgme_error_t
523     GpgKeyEdit::addSubkey (gpgme_pubkey_algo_t pubkey_algo, unsigned int pubkey_size,
524     long valid)
525     {
526     if (!this->key || !this->pass)
527     return gpg_error (GPG_ERR_INV_OBJ);
528    
529     type = GPG_EDITKEY_ADDKEY;
530     this->pubkey_algo = pubkey_algo;
531     this->pubkey_size = pubkey_size;
532     this->valid = valid;
533     return gpg_editkey (this->ctx, this->key, this);
534     }
535    
536     /* Change the passphrase of the given key to @new_pass.
537     If allow_empty != 0, it is allowed to provide an empty passphrase.
538     Return value: 0 on success. */
539     gpgme_error_t
540     GpgKeyEdit::changePassphrase (const char *new_pass, int allow_empty)
541     {
542     if (!this->key || !this->pass)
543     return gpg_error (GPG_ERR_INV_OBJ);
544    
545     type = GPG_EDITKEY_PASSWD;
546     this->new_pass = new_pass;
547     this->flags = allow_empty? 1 : 0;
548     return gpg_editkey (this->ctx, this->key, this);
549     }
550    
551     /* Set the primary user-ID of the given key to user-ID with
552     the index @uid_index.
553     Return value: 0 on success. */
554     gpgme_error_t
555     GpgKeyEdit::setPrimaryUserid (int uid_index)
556     {
557     if (!this->key || !this->pass)
558     return gpg_error (GPG_ERR_INV_OBJ);
559    
560     type = GPG_EDITKEY_PRIMARY;
561     this->uid_index = uid_index;
562     return gpg_editkey (this->ctx, this->key, this);
563     }
564    
565     /* Set the expire date of the subkey with the index @key_index.
566     @exp_timestamp is used to calculate the days the key is valid.
567 twoaday 25 if @exp_days is true, exp_timestamp is already converted to days.
568 twoaday 23 Return value: 0 on success. */
569     gpgme_error_t
570 twoaday 25 GpgKeyEdit::setKeyExpireDate (int key_index, long exp_timestamp, bool exp_days)
571 twoaday 23 {
572     if (!this->key || !this->pass)
573     return gpg_error (GPG_ERR_INV_OBJ);
574 twoaday 25 if (!exp_days && exp_timestamp > 0 && exp_timestamp < time (NULL))
575 twoaday 23 return gpg_error (GPG_ERR_INV_ARG);
576 twoaday 25
577     type = GPG_EDITKEY_EXPIRE;
578     if (!exp_days && exp_timestamp > 0) {
579 twoaday 23 valid = exp_timestamp - time (NULL);
580     valid /= 86400;
581     }
582 twoaday 25 else
583     valid = exp_timestamp;
584 twoaday 23 this->key_index = key_index;
585     return gpg_editkey (this->ctx, this->key, this);
586     }
587    
588 twoaday 25 /* Revoke the userid given by the index @uid_index.
589     Return value: 0 on success. */
590     gpgme_error_t
591     GpgKeyEdit::revokeUserid (int uid_index)
592     {
593     if (!this->key || !this->pass)
594     return gpg_error (GPG_ERR_INV_OBJ);
595 twoaday 23
596 twoaday 25 type = GPG_EDITKEY_REVUID;
597     this->uid_index = uid_index;
598     return gpg_editkey (this->ctx, this->key, this);
599     }
600    
601    
602 twoaday 23 /* Revoke a signature on the user-ID with the index @uid_index
603     and the signature index @sig_index.
604     Return value: 0 on success. */
605     gpgme_error_t
606     GpgKeyEdit::revokeSignature (int uid_index, int sig_index)
607     {
608     if (!this->key || !this->pass)
609     return gpg_error (GPG_ERR_INV_OBJ);
610    
611     type = GPG_EDITKEY_REVSIG;
612     this->uid_index = uid_index;
613     this->sig_index = sig_index;
614     return gpg_editkey (this->ctx, this->key, this);
615     }
616    
617    
618     /* Revoke the subkey with the index @key_index. Optionally
619     a reason can be provided in @reason with a text to describe
620     more details in @cmt.
621     Return value: 0 on success. */
622     gpgme_error_t
623     GpgKeyEdit::revokeSubkey (int key_index, int reason, const char *cmt)
624     {
625     if (!this->key || !this->pass)
626     return gpg_error (GPG_ERR_INV_OBJ);
627    
628     type = GPG_EDITKEY_REVKEY;
629     this->key_index = key_index;
630     this->reason = reason;
631     free_if_alloc (this->cmt);
632 twoaday 25 this->cmt = NULL;
633     if (cmt)
634     this->cmt = m_strdup (cmt);
635 twoaday 23 return gpg_editkey (this->ctx, this->key, this);
636     }
637    
638    
639     /* Add a designated revoker to the key. @uid stores
640     the user-ID of the key who is allowed to be a
641     designated revoker.
642     Return value: 0 on success. */
643     gpgme_error_t
644     GpgKeyEdit::addDesignatedRevoker (const char *uid)
645     {
646     if (!this->key || !this->pass)
647     return gpg_error (GPG_ERR_INV_OBJ);
648    
649     type = GPG_EDITKEY_ADDREV;
650     free_if_alloc (this->name);
651     this->name = m_strdup (uid);
652     return gpg_editkey (this->ctx, this->key, this);
653     }
654    
655     /* Add a photo-ID to the key. The JPG image is given
656     in the file with the name @jpg_file.
657     Return value: 0 on success. */
658     gpgme_error_t
659     GpgKeyEdit::addPhotoid (const char *jpg_file)
660     {
661     if (!this->key || !this->pass)
662     return gpg_error (GPG_ERR_INV_OBJ);
663    
664     type = GPG_EDITKEY_ADDPHOTO;
665     this->url = jpg_file;
666     return gpg_editkey (this->ctx, this->key, this);
667     }
668    
669     /* Enable the given key. */
670     gpgme_error_t
671     GpgKeyEdit::enable (void)
672     {
673     if (!this->key)
674     return gpg_error (GPG_ERR_INV_OBJ);
675     type = GPG_EDITKEY_ENABLE;
676     return gpg_editkey (this->ctx, this->key, this);
677     }
678    
679     /* Disable the given key. */
680     gpgme_error_t
681     GpgKeyEdit::disable (void)
682     {
683     if (!this->key)
684     return gpg_error (GPG_ERR_INV_OBJ);
685     type = GPG_EDITKEY_DISABLE;
686     return gpg_editkey (this->ctx, this->key, this);
687     }
688    
689    
690     /* Update the user-ID preferences of the user-ID with the
691     index @uid_index to the prefs given in @new_prefs.
692     Return value: 0 on success. */
693     gpgme_error_t
694     GpgKeyEdit::setUseridPreferences (int uid_index, const char *new_prefs)
695     {
696     if (!this->key || !this->pass)
697     return gpg_error (GPG_ERR_INV_OBJ);
698 twoaday 25 return 0;
699 twoaday 23 }
700    
701    
702     /* Delete a signature from the user-ID with the index @uid_index.
703     The index of the signature is given in @sig_index.
704     Return value: 0 on success. */
705     gpgme_error_t
706 twoaday 24 GpgKeyEdit::delUseridSignature (int uid_index, int sig_index)
707 twoaday 23 {
708     if (!this->key)
709     return gpg_error (GPG_ERR_INV_OBJ);
710     type = GPG_EDITKEY_DELSIG;
711     this->uid_index = uid_index;
712     this->sig_index = sig_index;
713     return gpg_editkey (this->ctx, this->key, this);
714     }
715    
716     /* Set the preferred keyserver for the given key to @url.
717     Return value: 0 on success. */
718     gpgme_error_t
719     GpgKeyEdit::setPreferredKeyserver (int uid_index, const char *url)
720     {
721     if (!this->key || !this->pass)
722     return gpg_error (GPG_ERR_INV_OBJ);
723     if (!url)
724     return gpg_error (GPG_ERR_INV_ARG);
725     type = GPG_EDITKEY_KEYSERV;
726     this->url = url;
727     this->uid_index = uid_index;
728     return gpg_editkey (this->ctx, this->key, this);
729     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26