First take on the low-level assuan interface.
[gpgme.git] / src / gpgme.c
1 /* gpgme.c - GnuPG Made Easy.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 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 Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (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    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <locale.h>
31
32 #include "util.h"
33 #include "context.h"
34 #include "ops.h"
35 #include "wait.h"
36 #include "debug.h"
37
38 \f
39 /* The default locale.  */
40 DEFINE_STATIC_LOCK (def_lc_lock);
41 static char *def_lc_ctype;
42 static char *def_lc_messages;
43
44 \f
45 /* Create a new context as an environment for GPGME crypto
46    operations.  */
47 gpgme_error_t
48 gpgme_new (gpgme_ctx_t *r_ctx)
49 {
50   gpgme_ctx_t ctx;
51   TRACE_BEG (DEBUG_CTX, "gpgme_new", r_ctx);
52
53   ctx = calloc (1, sizeof *ctx);
54   if (!ctx)
55     return TRACE_ERR (gpg_error_from_errno (errno));
56
57   INIT_LOCK (ctx->lock);
58   
59   _gpgme_engine_info_copy (&ctx->engine_info);
60   if (!ctx->engine_info)
61     {
62       free (ctx);
63       return TRACE_ERR (gpg_error_from_errno (errno));
64     }
65
66   ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
67   ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
68   ctx->protocol = GPGME_PROTOCOL_OpenPGP;
69   _gpgme_fd_table_init (&ctx->fdt);
70
71   LOCK (def_lc_lock);
72   if (def_lc_ctype)
73     {
74       ctx->lc_ctype = strdup (def_lc_ctype);
75       if (!ctx->lc_ctype)
76         {
77           UNLOCK (def_lc_lock);
78           _gpgme_engine_info_release (ctx->engine_info);
79           free (ctx);
80           return TRACE_ERR (gpg_error_from_errno (errno));
81         }
82     }
83   else
84     def_lc_ctype = NULL;
85
86   if (def_lc_messages)
87     {
88       ctx->lc_messages = strdup (def_lc_messages);
89       if (!ctx->lc_messages)
90         {
91           UNLOCK (def_lc_lock);
92           if (ctx->lc_ctype)
93             free (ctx->lc_ctype);
94           _gpgme_engine_info_release (ctx->engine_info);
95           free (ctx);
96           return TRACE_ERR (gpg_error_from_errno (errno));
97         }
98     }
99   else
100     def_lc_messages = NULL;
101   UNLOCK (def_lc_lock);
102
103   *r_ctx = ctx;
104
105   return TRACE_SUC1 ("ctx=%p", ctx);
106 }
107
108
109 gpgme_error_t
110 _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err)
111 {
112   gpgme_error_t err;
113   TRACE_BEG1 (DEBUG_CTX, "_gpgme_cancel_with_err", ctx, "ctx_err=%i",
114               ctx_err);
115
116   err = _gpgme_engine_cancel (ctx->engine);
117   if (err)
118     return TRACE_ERR (err);
119
120   _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &ctx_err);
121
122   return TRACE_ERR (0);
123 }
124
125
126 /* Cancel a pending asynchronous operation.  */
127 gpgme_error_t
128 gpgme_cancel (gpgme_ctx_t ctx)
129 {
130   return _gpgme_cancel_with_err (ctx, gpg_error (GPG_ERR_CANCELED));
131 }
132
133
134 /* Cancel a pending operation asynchronously.  */
135 gpgme_error_t
136 gpgme_cancel_async (gpgme_ctx_t ctx)
137 {
138   TRACE_BEG (DEBUG_CTX, "gpgme_cancel_async", ctx);
139
140   LOCK (ctx->lock);
141   ctx->canceled = 1;
142   UNLOCK (ctx->lock);
143
144   return TRACE_ERR (0);
145 }
146
147
148 /* Release all resources associated with the given context.  */
149 void
150 gpgme_release (gpgme_ctx_t ctx)
151 {
152   TRACE (DEBUG_CTX, "gpgme_release", ctx);
153
154   _gpgme_engine_release (ctx->engine);
155   _gpgme_fd_table_deinit (&ctx->fdt);
156   _gpgme_release_result (ctx);
157   gpgme_signers_clear (ctx);
158   gpgme_sig_notation_clear (ctx);
159   if (ctx->signers)
160     free (ctx->signers);
161   if (ctx->lc_ctype)
162     free (ctx->lc_ctype);
163   if (ctx->lc_messages)
164     free (ctx->lc_messages);
165   _gpgme_engine_info_release (ctx->engine_info);
166   DESTROY_LOCK (ctx->lock);
167   free (ctx);
168 }
169
170
171 void
172 _gpgme_release_result (gpgme_ctx_t ctx)
173 {
174   struct ctx_op_data *data = ctx->op_data;
175
176   while (data)
177     {
178       struct ctx_op_data *next_data = data->next;
179       if (data->cleanup)
180         (*data->cleanup) (data->hook);
181       free (data);
182       data = next_data;
183     }
184   ctx->op_data = NULL;
185 }
186
187
188 gpgme_error_t
189 gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
190 {
191   TRACE_BEG2 (DEBUG_CTX, "gpgme_set_protocol", ctx, "protocol=%i (%s)",
192               protocol, gpgme_get_protocol_name (protocol)
193               ? gpgme_get_protocol_name (protocol) : "unknown");
194
195   if (protocol != GPGME_PROTOCOL_OpenPGP
196       && protocol != GPGME_PROTOCOL_CMS
197       && protocol != GPGME_PROTOCOL_ASSUAN)
198     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
199
200   if (ctx->protocol != protocol)
201     {
202       /* Shut down the engine when switching protocols.  */
203       if (ctx->engine)
204         {
205           TRACE_LOG1 ("releasing ctx->engine=%p", ctx->engine);
206           _gpgme_engine_release (ctx->engine);
207           ctx->engine = NULL;
208         }
209
210       ctx->protocol = protocol;
211     }
212   return TRACE_ERR (0);
213 }
214
215
216 gpgme_protocol_t
217 gpgme_get_protocol (gpgme_ctx_t ctx)
218 {
219   TRACE2 (DEBUG_CTX, "gpgme_get_protocol", ctx,
220           "ctx->protocol=%i (%s)", ctx->protocol,
221           gpgme_get_protocol_name (ctx->protocol)
222           ? gpgme_get_protocol_name (ctx->protocol) : "unknown");
223   return ctx->protocol;
224 }
225
226
227 const char *
228 gpgme_get_protocol_name (gpgme_protocol_t protocol)
229 {
230   switch (protocol)
231     {
232     case GPGME_PROTOCOL_OpenPGP:
233       return "OpenPGP";
234
235     case GPGME_PROTOCOL_CMS:
236       return "CMS";
237
238     case GPGME_PROTOCOL_ASSUAN:
239       return "Assuan";
240
241     case GPGME_PROTOCOL_UNKNOWN:
242       return "unknown";
243
244     default:
245       return NULL;
246     }
247 }
248
249 /* Enable or disable the use of an ascii armor for all output.  */
250 void
251 gpgme_set_armor (gpgme_ctx_t ctx, int use_armor)
252 {
253   TRACE2 (DEBUG_CTX, "gpgme_set_armor", ctx, "use_armor=%i (%s)",
254           use_armor, use_armor ? "yes" : "no");
255   ctx->use_armor = use_armor;
256 }
257
258
259 /* Return the state of the armor flag.  */
260 int
261 gpgme_get_armor (gpgme_ctx_t ctx)
262 {
263   TRACE2 (DEBUG_CTX, "gpgme_get_armor", ctx, "ctx->use_armor=%i (%s)",
264           ctx->use_armor, ctx->use_armor ? "yes" : "no");
265   return ctx->use_armor;
266 }
267
268
269 /* Enable or disable the use of the special textmode.  Textmode is for
270   example used for the RFC2015 signatures; note that the updated RFC
271   3156 mandates that the MUA does some preparations so that textmode
272   is not needed anymore.  */
273 void
274 gpgme_set_textmode (gpgme_ctx_t ctx, int use_textmode)
275 {
276   TRACE2 (DEBUG_CTX, "gpgme_set_textmode", ctx, "use_textmode=%i (%s)",
277           use_textmode, use_textmode ? "yes" : "no");
278   ctx->use_textmode = use_textmode;
279 }
280
281 /* Return the state of the textmode flag.  */
282 int
283 gpgme_get_textmode (gpgme_ctx_t ctx)
284 {
285   TRACE2 (DEBUG_CTX, "gpgme_get_textmode", ctx, "ctx->use_textmode=%i (%s)",
286           ctx->use_textmode, ctx->use_textmode ? "yes" : "no");
287   return ctx->use_textmode;
288 }
289
290
291 /* Set the number of certifications to include in an S/MIME message.
292    The default is GPGME_INCLUDE_CERTS_DEFAULT.  -1 means all certs,
293    and -2 means all certs except the root cert.  */
294 void
295 gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs)
296 {
297   if (nr_of_certs == GPGME_INCLUDE_CERTS_DEFAULT)
298     ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
299   else if (nr_of_certs < -2)
300     ctx->include_certs = -2;
301   else
302     ctx->include_certs = nr_of_certs;
303
304   TRACE2 (DEBUG_CTX, "gpgme_set_include_certs", ctx, "nr_of_certs=%i%s",
305           nr_of_certs, nr_of_certs == ctx->include_certs ? "" : " (-2)");
306 }
307
308
309 /* Get the number of certifications to include in an S/MIME
310    message.  */
311 int
312 gpgme_get_include_certs (gpgme_ctx_t ctx)
313 {
314   TRACE1 (DEBUG_CTX, "gpgme_get_include_certs", ctx, "ctx->include_certs=%i",
315           ctx->include_certs);
316   return ctx->include_certs;
317 }
318
319
320 /* This function changes the default behaviour of the keylisting
321    functions.  MODE is a bitwise-OR of the GPGME_KEYLIST_* flags.  The
322    default mode is GPGME_KEYLIST_MODE_LOCAL.  */
323 gpgme_error_t
324 gpgme_set_keylist_mode (gpgme_ctx_t ctx, gpgme_keylist_mode_t mode)
325 {
326   TRACE1 (DEBUG_CTX, "gpgme_set_keylist_mode", ctx, "keylist_mode=0x%x",
327           mode);
328
329   ctx->keylist_mode = mode;
330   return 0;
331 }
332
333 /* This function returns the default behaviour of the keylisting
334    functions.  */
335 gpgme_keylist_mode_t
336 gpgme_get_keylist_mode (gpgme_ctx_t ctx)
337 {
338   TRACE1 (DEBUG_CTX, "gpgme_get_keylist_mode", ctx,
339           "ctx->keylist_mode=0x%x", ctx->keylist_mode);
340   return ctx->keylist_mode;
341 }
342
343
344 /* This function sets a callback function to be used to pass a
345    passphrase to gpg.  */
346 void
347 gpgme_set_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb,
348                          void *cb_value)
349 {
350   TRACE2 (DEBUG_CTX, "gpgme_set_passphrase_cb", ctx,
351           "passphrase_cb=%p/%p", cb, cb_value);
352   ctx->passphrase_cb = cb;
353   ctx->passphrase_cb_value = cb_value;
354 }
355
356
357 /* This function returns the callback function to be used to pass a
358    passphrase to the crypto engine.  */
359 void
360 gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *r_cb,
361                          void **r_cb_value)
362 {
363   TRACE2 (DEBUG_CTX, "gpgme_get_passphrase_cb", ctx,
364           "ctx->passphrase_cb=%p/%p",
365           ctx->passphrase_cb, ctx->passphrase_cb_value);
366   if (r_cb)
367     *r_cb = ctx->passphrase_cb;
368   if (r_cb_value)
369     *r_cb_value = ctx->passphrase_cb_value;
370 }
371
372
373 /* This function sets a callback function to be used as a progress
374    indicator.  */
375 void
376 gpgme_set_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t cb, void *cb_value)
377 {
378   TRACE2 (DEBUG_CTX, "gpgme_set_progress_cb", ctx, "progress_cb=%p/%p",
379           cb, cb_value);
380   ctx->progress_cb = cb;
381   ctx->progress_cb_value = cb_value;
382 }
383
384
385 /* This function returns the callback function to be used as a
386    progress indicator.  */
387 void
388 gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb,
389                        void **r_cb_value)
390 {
391   TRACE2 (DEBUG_CTX, "gpgme_get_progress_cb", ctx, "ctx->progress_cb=%p/%p",
392           ctx->progress_cb, ctx->progress_cb_value);
393   if (r_cb)
394     *r_cb = ctx->progress_cb;
395   if (r_cb_value)
396     *r_cb_value = ctx->progress_cb_value;
397 }
398
399
400 /* Set the I/O callback functions for CTX to IO_CBS.  */
401 void
402 gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
403 {
404   if (io_cbs)
405     {
406       TRACE6 (DEBUG_CTX, "gpgme_set_io_cbs", ctx,
407               "io_cbs=%p (add=%p/%p, remove=%p, event=%p/%p",
408               io_cbs, io_cbs->add, io_cbs->add_priv, io_cbs->remove,
409               io_cbs->event, io_cbs->event_priv);
410       ctx->io_cbs = *io_cbs;
411     }
412   else
413     {
414       TRACE1 (DEBUG_CTX, "gpgme_set_io_cbs", ctx,
415               "io_cbs=%p (default)", io_cbs);
416       ctx->io_cbs.add = NULL;
417       ctx->io_cbs.add_priv = NULL;
418       ctx->io_cbs.remove = NULL;
419       ctx->io_cbs.event = NULL;
420       ctx->io_cbs.event_priv = NULL;
421     }
422 }
423
424
425 /* This function returns the callback function for I/O.  */
426 void
427 gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
428 {
429   TRACE6 (DEBUG_CTX, "gpgme_get_io_cbs", ctx,
430           "io_cbs=%p, ctx->io_cbs.add=%p/%p, .remove=%p, .event=%p/%p",
431           io_cbs, io_cbs->add, io_cbs->add_priv, io_cbs->remove,
432           io_cbs->event, io_cbs->event_priv);
433
434   *io_cbs = ctx->io_cbs;
435 }
436
437 \f
438 /* This function sets the locale for the context CTX, or the default
439    locale if CTX is a null pointer.  */
440 gpgme_error_t
441 gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
442 {
443   int failed = 0;
444   char *new_lc_ctype = NULL;
445   char *new_lc_messages = NULL;
446
447   TRACE_BEG2 (DEBUG_CTX, "gpgme_set_locale", ctx,
448                "category=%i, value=%s", category, value ? value : "(null)");
449
450 #define PREPARE_ONE_LOCALE(lcat, ucat)                          \
451   if (!failed && value                                          \
452       && (category == LC_ALL || category == LC_ ## ucat))       \
453     {                                                           \
454       new_lc_ ## lcat = strdup (value);                         \
455       if (!new_lc_ ## lcat)                                     \
456         failed = 1;                                             \
457     }
458
459   PREPARE_ONE_LOCALE (ctype, CTYPE);
460 #ifdef LC_MESSAGES
461   PREPARE_ONE_LOCALE (messages, MESSAGES);
462 #endif
463
464   if (failed)
465     {
466       int saved_errno = errno;
467
468       if (new_lc_ctype)
469         free (new_lc_ctype);
470       if (new_lc_messages)
471         free (new_lc_messages);
472
473       return TRACE_ERR (gpg_error_from_errno (saved_errno));
474     }
475
476 #define SET_ONE_LOCALE(lcat, ucat)                      \
477   if (category == LC_ALL || category == LC_ ## ucat)    \
478     {                                                   \
479       if (ctx)                                          \
480         {                                               \
481           if (ctx->lc_ ## lcat)                         \
482             free (ctx->lc_ ## lcat);                    \
483           ctx->lc_ ## lcat = new_lc_ ## lcat;           \
484         }                                               \
485       else                                              \
486         {                                               \
487           if (def_lc_ ## lcat)                          \
488             free (def_lc_ ## lcat);                     \
489           def_lc_ ## lcat = new_lc_ ## lcat;            \
490         }                                               \
491     }
492
493   if (!ctx)
494     LOCK (def_lc_lock);
495   SET_ONE_LOCALE (ctype, CTYPE);
496 #ifdef LC_MESSAGES
497   SET_ONE_LOCALE (messages, MESSAGES);
498 #endif
499   if (!ctx)
500     UNLOCK (def_lc_lock);
501
502   return TRACE_ERR (0);
503 }
504
505 \f
506 /* Get the information about the configured engines.  A pointer to the
507    first engine in the statically allocated linked list is returned.
508    The returned data is valid until the next gpgme_ctx_set_engine_info.  */
509 gpgme_engine_info_t
510 gpgme_ctx_get_engine_info (gpgme_ctx_t ctx)
511 {
512   TRACE1 (DEBUG_CTX, "gpgme_ctx_get_engine_info", ctx,
513           "ctx->engine_info=%p", ctx->engine_info);
514   return ctx->engine_info;
515 }
516
517
518 /* Set the engine info for the context CTX, protocol PROTO, to the
519    file name FILE_NAME and the home directory HOME_DIR.  */
520 gpgme_error_t
521 gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
522                            const char *file_name, const char *home_dir)
523 {
524   gpgme_error_t err;
525   TRACE_BEG4 (DEBUG_CTX, "gpgme_ctx_set_engine_info", ctx,
526               "protocol=%i (%s), file_name=%s, home_dir=%s",
527               proto, gpgme_get_protocol_name (proto)
528               ? gpgme_get_protocol_name (proto) : "unknown",
529               file_name ? file_name : "(default)",
530               home_dir ? home_dir : "(default)");
531               
532   /* Shut down the engine when changing engine info.  */
533   if (ctx->engine)
534     {
535       TRACE_LOG1 ("releasing ctx->engine=%p", ctx->engine);
536       _gpgme_engine_release (ctx->engine);
537       ctx->engine = NULL;
538     }
539   err = _gpgme_set_engine_info (ctx->engine_info, proto,
540                                 file_name, home_dir);
541   return TRACE_ERR (err);
542 }
543
544 \f
545 /* Clear all notation data from the context.  */
546 void
547 gpgme_sig_notation_clear (gpgme_ctx_t ctx)
548 {
549   gpgme_sig_notation_t notation;
550   TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx);
551
552   if (!ctx)
553     return;
554
555   notation = ctx->sig_notations;
556   while (notation)
557     {
558       gpgme_sig_notation_t next_notation = notation->next;
559       _gpgme_sig_notation_free (notation);
560       notation = next_notation;
561     }
562   ctx->sig_notations = NULL;
563 }
564
565
566 /* Add the human-readable notation data with name NAME and value VALUE
567    to the context CTX, using the flags FLAGS.  If NAME is NULL, then
568    VALUE should be a policy URL.  The flag
569    GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
570    data, and false for policy URLs.  */
571 gpgme_error_t
572 gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
573                         const char *value, gpgme_sig_notation_flags_t flags)
574 {
575   gpgme_error_t err;
576   gpgme_sig_notation_t notation;
577   gpgme_sig_notation_t *lastp;
578
579   TRACE_BEG3 (DEBUG_CTX, "gpgme_sig_notation_add", ctx,
580               "name=%s, value=%s, flags=0x%x",
581               name ? name : "(null)", value ? value : "(null)",
582               flags);
583   
584   if (!ctx)
585     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
586
587   if (name)
588     flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
589   else
590     flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE;
591
592   err = _gpgme_sig_notation_create (&notation, name, name ? strlen (name) : 0,
593                                     value, value ? strlen (value) : 0, flags);
594   if (err)
595     return TRACE_ERR (err);
596
597   lastp = &ctx->sig_notations;
598   while (*lastp)
599     lastp = &(*lastp)->next;
600
601   *lastp = notation;
602   return TRACE_ERR (0);
603 }
604
605
606 /* Get the sig notations for this context.  */
607 gpgme_sig_notation_t
608 gpgme_sig_notation_get (gpgme_ctx_t ctx)
609 {
610   if (!ctx)
611     {
612       TRACE (DEBUG_CTX, "gpgme_sig_notation_get", ctx);
613       return NULL;
614     }
615   TRACE1 (DEBUG_CTX, "gpgme_sig_notation_get", ctx,
616           "ctx->sig_notations=%p", ctx->sig_notations);
617
618   return ctx->sig_notations;
619 }
620   
621 \f
622 const char *
623 gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
624 {
625   switch (algo)
626     {
627     case GPGME_PK_RSA:
628       return "RSA";
629
630     case GPGME_PK_RSA_E:
631       return "RSA-E";
632
633     case GPGME_PK_RSA_S:
634       return "RSA-S";
635
636     case GPGME_PK_ELG_E:
637       return "ELG-E";
638
639     case GPGME_PK_DSA:
640       return "DSA";
641
642     case GPGME_PK_ELG:
643       return "ELG";
644
645     default:
646       return NULL;
647     }
648 }
649
650
651 const char *
652 gpgme_hash_algo_name (gpgme_hash_algo_t algo)
653 {
654   switch (algo)
655     {
656     case GPGME_MD_MD5:
657       return "MD5";
658
659     case GPGME_MD_SHA1:
660       return "SHA1";
661
662     case GPGME_MD_RMD160:
663       return "RIPEMD160";
664
665     case GPGME_MD_MD2:
666       return "MD2";
667
668     case GPGME_MD_TIGER:
669       return "TIGER192";
670
671     case GPGME_MD_HAVAL:
672       return "HAVAL";
673
674     case GPGME_MD_SHA256:
675       return "SHA256";
676
677     case GPGME_MD_SHA384:
678       return "SHA384";
679
680     case GPGME_MD_SHA512:
681       return "SHA512";
682
683     case GPGME_MD_MD4:
684       return "MD4";
685
686     case GPGME_MD_CRC32:
687       return "CRC32";
688
689     case GPGME_MD_CRC32_RFC1510:
690       return "CRC32RFC1510";
691
692     case GPGME_MD_CRC24_RFC2440:
693       return "CRC24RFC2440";
694
695     default:
696       return NULL;
697     }
698 }