-fixing last FTBFS issues
[oweals/gnunet.git] / src / conversation / conversation_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file conversation/conversation_api.c
23  * @brief API for conversation
24  * @author Simon Dieterle
25  * @author Andreas Fuchs
26  * STRUCTURE:
27  * - DATA STRUCTURES
28  * - DECLARATIONS
29  * - AUXILIARY FUNCTIONS
30  * - RECEIVE HANDLERS
31  * - SEND FUNCTIONS
32  * - API CALL DEFINITIONS
33  *
34  */
35
36 #include "platform.h"
37 #include "gnunet_util_lib.h"
38 #include "gnunet_dnsparser_lib.h"
39 #include "gnunet_gns_service.h"
40 #include "gnunet_protocols_conversation.h"
41 #include "gnunet_conversation_service.h"
42
43 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
44
45 /******************************************************************************/
46 /************************      DATA STRUCTURES     ****************************/
47 /******************************************************************************/
48
49 enum GNUNET_CONVERSATION_CallType
50 {
51   CALLER = 0,
52   CALLEE
53 };
54
55 /**
56 * Information about a call
57 */
58 struct GNUNET_CONVERSATION_CallInformation
59 {
60
61         /**
62         * Peer interacting with
63         */
64   struct GNUNET_PeerIdentity peer;
65
66         /**
67         * Type of call (incoming or outgoing)
68         */
69   int type;
70
71         /**
72         * Shows if the call ist fully established
73         */
74   int established;
75 };
76
77 /**
78  * Opaque handle to the service.
79  */
80 struct GNUNET_CONVERSATION_Handle
81 {
82
83         /**
84         * Our configuration.
85         */
86   const struct GNUNET_CONFIGURATION_Handle *cfg;
87
88     /**
89      * Handle to the server connection, to send messages later
90      */
91   struct GNUNET_CLIENT_Connection *client;
92
93    /**
94         * GNS handle
95         */
96   struct GNUNET_GNS_Handle *gns;
97
98         /**
99         * Namestore handle
100         */
101   struct GNUNET_NAMESTORE_Handle *namestore;
102
103         /**
104         * TXT record for gns
105         */
106   int txt_record_set;
107
108         /**
109      * Callback for incoming calls
110      */
111   GNUNET_CONVERSATION_CallHandler *call_handler;
112
113         /**
114      * Callback for rejected calls
115      */
116   GNUNET_CONVERSATION_RejectHandler *reject_handler;
117
118         /**
119      * Callback for notifications
120      */
121   GNUNET_CONVERSATION_NotificationHandler *notification_handler;
122
123         /**
124      * Callback for missed calls
125      */
126   GNUNET_CONVERSATION_MissedCallHandler *missed_call_handler;
127
128         /**
129         * The pointer to the call
130         */
131   struct GNUNET_CONVERSATION_CallInformation *call;
132 };
133
134 /******************************************************************************/
135 /***********************     AUXILIARY FUNCTIONS      *************************/
136 /******************************************************************************/
137
138 /**
139 * Initialize the conversation txt record in GNS
140 */
141 static void
142 setup_gns_txt (struct GNUNET_CONVERSATION_Handle *handle)
143 {
144   struct GNUNET_CRYPTO_EccPublicSignKey zone_pkey;
145   struct GNUNET_CRYPTO_EccPrivateKey *zone_key;
146   struct GNUNET_CRYPTO_EccPrivateKey *peer_key;
147   struct GNUNET_NAMESTORE_RecordData rd;
148   struct GNUNET_PeerIdentity peer;
149
150   char *zone_keyfile;
151   char *peer_keyfile;
152
153   rd.expiration_time = UINT64_MAX;
154
155   if (GNUNET_OK !=
156       GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "gns", "ZONEKEY",
157                                                &zone_keyfile))
158     {
159       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
160       return;
161     }
162
163   if (GNUNET_OK !=
164       GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "PEER",
165                                                "PRIVATE_KEY", &peer_keyfile))
166     {
167       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
168       return;
169     }
170
171   zone_key = GNUNET_CRYPTO_ecc_key_create_from_file (zone_keyfile);
172   GNUNET_CRYPTO_ecc_key_get_public_for_signature (zone_key, &zone_pkey);
173   peer_key = GNUNET_CRYPTO_ecc_key_create_from_file (peer_keyfile);
174   GNUNET_CRYPTO_ecc_key_get_public_for_signature (peer_key,
175                                                   &peer.public_key);
176   const char *h = GNUNET_i2s_full (&peer);
177
178   rd.data_size = strlen (h) + 1;
179   rd.data = h;
180   rd.record_type = GNUNET_DNSPARSER_TYPE_TXT;
181   rd.flags = GNUNET_NAMESTORE_RF_NONE;
182
183   /* FIXME: continuation? return value? */
184   GNUNET_NAMESTORE_records_store (handle->namestore, 
185                                   zone_key,
186                                   "conversation", 
187                                   1, &rd,
188                                   NULL, NULL);
189 }
190
191 /**
192 * Callback for checking the conversation txt gns record
193 *
194 * @param cls closure
195 * @param rd_count
196 * @param rd
197 */
198 static void
199 check_gns_cb (void *cls, uint32_t rd_count,
200               const struct GNUNET_NAMESTORE_RecordData *rd)
201 {
202   struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
203
204   if (0 == rd_count)
205     {
206       setup_gns_txt (h);
207     }
208   else
209     {
210       h->txt_record_set = GNUNET_YES;
211     }
212
213   return;
214 }
215
216 /**
217 * Check if the gns txt record for conversation exits
218 */
219 static void
220 check_gns (struct GNUNET_CONVERSATION_Handle *h)
221 {
222   GNUNET_GNS_lookup (h->gns, "conversation.gads", 
223                      NULL /* FIXME_ZONE */,
224                      GNUNET_DNSPARSER_TYPE_TXT,
225                      GNUNET_NO, 
226                      NULL, 
227                      &check_gns_cb, h);
228
229   return;
230 }
231
232 /******************************************************************************/
233 /***********************      RECEIVE HANDLERS     ****************************/
234 /******************************************************************************/
235
236 /**
237  * Function to process all messages received from the service
238  *
239  * @param cls closure
240  * @param msg message received, NULL on timeout or fatal error
241  */
242 static void
243 receive_message_cb (void *cls, const struct GNUNET_MessageHeader *msg)
244 {
245   struct GNUNET_CONVERSATION_Handle *h = cls;
246   struct ServerClientSessionInitiateMessage *imsg;
247   struct ServerClientSessionRejectMessage *rmsg;
248   struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls;
249
250   if (NULL != msg)
251     {
252       switch (ntohs (msg->type))
253         {
254         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT:
255           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
256                       _("%s has accepted your call.\n"),
257                       GNUNET_i2s_full (&(h->call->peer)));
258
259           h->notification_handler (NULL, h, NotificationType_CALL_ACCEPTED,
260                                    &(h->call->peer));
261           h->call->type = CALLEE;
262
263           break;
264
265         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT:
266           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267                       _("%s has rejected your call.\n"),
268                       GNUNET_i2s_full (&(h->call->peer)));
269
270           rmsg = (struct ServerClientSessionRejectMessage *) msg;
271           h->reject_handler (NULL, h, ntohs (rmsg->reason), &(h->call->peer));
272           GNUNET_free (h->call);
273           h->call = NULL;
274
275           break;
276
277         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE:
278           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
279                       _("%s has terminated the call.\n"),
280                       GNUNET_i2s_full (&(h->call->peer)));
281
282           h->notification_handler (NULL, h, NotificationType_CALL_TERMINATED,
283                                    &(h->call->peer));
284           GNUNET_free (h->call);
285           h->call = NULL;
286
287           break;
288
289         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE:
290           imsg = (struct ServerClientSessionInitiateMessage *) msg;
291
292           GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s wants to call you.\n"),
293                       GNUNET_i2s_full (&(imsg->peer)));
294
295           h->call =
296             (struct GNUNET_CONVERSATION_CallInformation *)
297             GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
298           memcpy (&(h->call->peer), &(imsg->peer),
299                   sizeof (struct GNUNET_PeerIdentity));
300           h->call_handler (NULL, h, &(h->call->peer));
301           h->call->type = CALLEE;
302
303           break;
304
305         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL:
306           missed_calls =
307             (struct GNUNET_CONVERSATION_MissedCallNotification *) (msg +
308                                                            (sizeof
309                                                             (struct
310                                                              GNUNET_MessageHeader)));
311           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312                       _("You &d have missed a calls.\n"),
313                       missed_calls->number);
314           h->missed_call_handler (NULL, h, missed_calls);
315           break;
316
317         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED:
318           GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("The service is blocked.\n"));
319           h->notification_handler (NULL, h, NotificationType_SERVICE_BLOCKED,
320                                    NULL);
321           break;
322
323         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED:
324           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
325                       _("The peer you are calling is not connected.\n"));
326           h->notification_handler (NULL, h, NotificationType_NO_PEER, NULL);
327           break;
328
329         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER:
330           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
331                       _("The peer you are calling does not answer.\n"));
332           h->notification_handler (NULL, h, NotificationType_NO_ANSWER,
333                                    &(h->call->peer));
334           break;
335
336         case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR:
337           GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Generic error occured.\n"));
338           break;
339
340         default:
341           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
342                       _("Got unknown message type.\n"));
343           break;
344         }
345
346     }
347
348   GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
349                          GNUNET_TIME_UNIT_FOREVER_REL);
350 }
351
352 /******************************************************************************/
353 /************************       SEND FUNCTIONS     ****************************/
354 /******************************************************************************/
355
356 /**
357  * Function called to send a session initiate message to the service.
358  * "buf" will be NULL and "size" zero if the socket was closed for writing in
359  * the meantime.
360  *
361  * @param cls closure, NULL
362  * @param size number of bytes available in buf
363  * @param buf where the callee should write the initiate message
364  * @return number of bytes written to buf
365  */
366 static size_t
367 transmit_session_initiate_message (void *cls, size_t size, void *buf)
368 {
369   size_t msg_size;
370   struct ClientServerSessionInitiateMessage *msg;
371   struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
372
373   msg_size = sizeof (struct ClientServerSessionInitiateMessage);
374
375   GNUNET_assert (size >= msg_size);
376   msg = buf;
377   msg->header.size = htons (msg_size);
378   msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE);
379   memcpy (&msg->peer, &(h->call->peer), sizeof (struct GNUNET_PeerIdentity));
380
381   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382               _
383               ("Sending ClientServerSessionInitiateMessage to the service for peer: %s\n"),
384               GNUNET_i2s_full (&(h->call->peer)));
385
386   h->call->type = CALLER;
387
388   return msg_size;
389 }
390
391 /**
392  * Function called to send a session accept message to the service.
393  * "buf" will be NULL and "size" zero if the socket was closed for writing in
394  * the meantime.
395  *
396  * @param cls closure, NULL
397  * @param size number of bytes available in buf
398  * @param buf where the callee should write the accept message
399  * @return number of bytes written to buf
400  */
401 static size_t
402 transmit_session_accept_message (void *cls, size_t size, void *buf)
403 {
404   size_t msg_size;
405   struct ClientServerSessionAcceptMessage *msg;
406   struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
407
408   msg_size = sizeof (struct ClientServerSessionAcceptMessage);
409
410   GNUNET_assert (size >= msg_size);
411   msg = buf;
412   msg->header.size = htons (msg_size);
413   msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT);
414
415   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
416               _
417               ("Sending ClienServerSessionAcceptMessage to the service for peer: %s\n"),
418               GNUNET_i2s_full (&(h->call->peer)));
419
420   h->call->established = GNUNET_YES;
421
422   return msg_size;
423 }
424
425 /**
426  * Function called to send a session reject message to the service.
427  * "buf" will be NULL and "size" zero if the socket was closed for writing in
428  * the meantime.
429  *
430  * @param cls closure, NULL
431  * @param size number of bytes available in buf
432  * @param buf where the callee should write the reject message
433  * @return number of bytes written to buf
434  */
435 static size_t
436 transmit_session_reject_message (void *cls, size_t size, void *buf)
437 {
438   size_t msg_size;
439   struct ClientServerSessionRejectMessage *msg;
440   struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
441
442   msg_size = sizeof (struct ClientServerSessionRejectMessage);
443
444   GNUNET_assert (size >= msg_size);
445   msg = buf;
446   msg->header.size = htons (msg_size);
447   msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT);
448   msg->reason = htons (REJECT_REASON_NOT_WANTED);
449
450   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
451               _
452               ("Sending ClientServerSessionRejectMessage to the service for peer: %s\n"),
453               GNUNET_i2s_full (&(h->call->peer)));
454
455   GNUNET_free (h->call);
456   h->call = NULL;
457
458   return msg_size;
459 }
460
461 /**
462  * Function called to send a session terminate message to the service.
463  * "buf" will be NULL and "size" zero if the socket was closed for writing in
464  * the meantime.
465  *
466  * @param cls closure, NULL
467  * @param size number of bytes available in buf
468  * @param buf where the callee should write the terminate message
469  * @return number of bytes written to buf
470  */
471 static size_t
472 transmit_session_terminate_message (void *cls, size_t size, void *buf)
473 {
474   size_t msg_size;
475   struct ClientServerSessionTerminateMessage *msg;
476   struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
477
478   msg_size = sizeof (struct ClientServerSessionTerminateMessage);
479
480   GNUNET_assert (size >= msg_size);
481   msg = buf;
482   msg->header.size = htons (msg_size);
483   msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE);
484
485   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
486               _
487               ("Sending ClientServerSessionTerminateMessage to the service for peer: %s\n"),
488               GNUNET_i2s_full (&(h->call->peer)));
489
490   GNUNET_free (h->call);
491   h->call = NULL;
492
493   return msg_size;
494 }
495
496 /**
497  * Auxiliary function to call a peer.
498  * 
499  * @param h conversation handle
500  * @return 
501  */
502 static void
503 initiate_call (struct GNUNET_CONVERSATION_Handle *h, struct GNUNET_PeerIdentity peer)
504 {
505   h->call =
506     (struct GNUNET_CONVERSATION_CallInformation *)
507     GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
508   memcpy (&(h->call->peer), &peer, sizeof (struct GNUNET_PeerIdentity));
509
510   GNUNET_CLIENT_notify_transmit_ready (h->client,
511                                        sizeof (struct
512                                                ClientServerSessionInitiateMessage),
513                                        MAX_TRANSMIT_DELAY, GNUNET_YES,
514                                        &transmit_session_initiate_message, h);
515
516   return;
517 }
518
519 /**
520  * Auxiliary function to accept a call.
521  * 
522  * @param h conversation handle
523  */
524 static void
525 accept_call (struct GNUNET_CONVERSATION_Handle *h)
526 {
527   GNUNET_CLIENT_notify_transmit_ready (h->client,
528                                        sizeof (struct
529                                                ClientServerSessionAcceptMessage),
530                                        MAX_TRANSMIT_DELAY, GNUNET_YES,
531                                        &transmit_session_accept_message, h);
532 }
533
534 /**
535  * Auxiliary function to reject a call.
536  * 
537  * @param h conversation handle
538  */
539 static void
540 reject_call (struct GNUNET_CONVERSATION_Handle *h)
541 {
542   GNUNET_CLIENT_notify_transmit_ready (h->client,
543                                        sizeof (struct
544                                                ClientServerSessionRejectMessage),
545                                        MAX_TRANSMIT_DELAY, GNUNET_YES,
546                                        &transmit_session_reject_message, h);
547 }
548
549 /**
550  * Auxiliary function to terminate a call.
551  * 
552  * @param h conversation handle
553  */
554 static void
555 terminate_call (struct GNUNET_CONVERSATION_Handle *h)
556 {
557   GNUNET_CLIENT_notify_transmit_ready (h->client,
558                                        sizeof (struct
559                                                ClientServerSessionTerminateMessage),
560                                        MAX_TRANSMIT_DELAY, GNUNET_YES,
561                                        &transmit_session_terminate_message,
562                                        h);
563 }
564
565 /**
566 *
567 */
568 static void
569 gns_call_cb (void *cls, uint32_t rd_count,
570              const struct GNUNET_NAMESTORE_RecordData *rd)
571 {
572   struct GNUNET_CONVERSATION_Handle *handle = cls;
573   struct GNUNET_PeerIdentity peer;
574   unsigned int i;
575
576   for (i=0;i<rd_count;i++)
577   {
578     switch (rd[i].record_type)
579     {
580     case GNUNET_DNSPARSER_TYPE_TXT: /* FIXME:  use fresh record type for voide... */
581       if (GNUNET_OK !=
582           GNUNET_CRYPTO_ecc_public_sign_key_from_string (rd[i].data,
583                                                          rd[i].data_size,
584                                                          &peer.public_key))
585       {
586         GNUNET_break_op (0);
587         continue;
588       }      
589       initiate_call (handle, peer);
590       return;
591     default:
592       break;
593     }
594   }
595   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
596               "Lookup failed\n");
597   handle->notification_handler (NULL, handle, 
598                                 NotificationType_NO_PEER,
599                                 NULL);
600 }
601
602
603 /**
604 * GNS lookup
605 */
606 static void
607 gns_lookup_and_call (struct GNUNET_CONVERSATION_Handle *h, const char *callee)
608 {
609   char domain[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
610   char *pos;
611
612   pos = domain;
613   strcpy (pos, "conversation");
614   pos += strlen ("conversation");
615   strcpy (pos, ".");
616   pos++;
617   strcpy (pos, callee);
618   pos += strlen (callee);
619
620   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup for %s\n", domain);
621
622   GNUNET_GNS_lookup (h->gns,
623                      domain,
624                      NULL /* FIXME: ZONE! */,
625                      GNUNET_DNSPARSER_TYPE_TXT,
626                      GNUNET_NO, 
627                      NULL,
628                      &gns_call_cb, h);
629 }
630
631
632 /******************************************************************************/
633 /**********************      API CALL DEFINITIONS     *************************/
634 /******************************************************************************/
635
636 struct GNUNET_CONVERSATION_Handle *
637 GNUNET_CONVERSATION_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
638                      GNUNET_CONVERSATION_CallHandler * call_handler,
639                      GNUNET_CONVERSATION_RejectHandler * reject_handler,
640                      GNUNET_CONVERSATION_NotificationHandler * notification_handler,
641                      GNUNET_CONVERSATION_MissedCallHandler * missed_call_handler)
642 {
643   struct GNUNET_CONVERSATION_Handle *h;
644
645   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNUNET_CONVERSATION_connect()\n");
646   h = GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_Handle));
647
648   h->cfg = cfg;
649   h->call_handler = call_handler;
650   h->reject_handler = reject_handler;
651   h->notification_handler = notification_handler;
652   h->missed_call_handler = missed_call_handler;
653
654   if (NULL == (h->client = GNUNET_CLIENT_connect ("conversation", cfg)))
655     {
656       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access CONVERSATION service\n");
657       GNUNET_break (0);
658       GNUNET_free (h);
659
660       return NULL;
661     }
662
663   if (NULL == (h->gns = GNUNET_GNS_connect (cfg)))
664     {
665       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access GNS service\n");
666       GNUNET_break (0);
667       GNUNET_CLIENT_disconnect (h->client);
668       GNUNET_free (h);
669
670       return NULL;
671     }
672
673   if (NULL == (h->namestore = GNUNET_NAMESTORE_connect (cfg)))
674     {
675       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
676                   "Could not access NAMESTORE service\n");
677       GNUNET_break (0);
678       GNUNET_CLIENT_disconnect (h->client);
679       GNUNET_GNS_disconnect (h->gns);
680       GNUNET_free (h);
681
682       return NULL;
683     }
684
685   check_gns (h);
686   GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
687                          GNUNET_TIME_UNIT_FOREVER_REL);
688
689   return h;
690 }
691
692 void
693 GNUNET_CONVERSATION_disconnect (struct GNUNET_CONVERSATION_Handle *handle)
694 {
695   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CONVERSATION DISCONNECT\n");
696
697   GNUNET_CLIENT_disconnect (handle->client);
698   GNUNET_GNS_disconnect (handle->gns);
699
700   GNUNET_free (handle);
701   handle = NULL;
702 }
703
704
705 void
706 GNUNET_CONVERSATION_call (struct GNUNET_CONVERSATION_Handle *h, 
707                           const char *callee,
708                           int doGnsLookup)
709 {
710   struct GNUNET_PeerIdentity peer;
711
712   if (NULL == h || NULL == h->client)
713     return;
714
715   if (GNUNET_YES == doGnsLookup)
716   {
717     gns_lookup_and_call (h, callee);
718     return;
719   }
720   if (GNUNET_OK !=
721       GNUNET_CRYPTO_ecc_public_sign_key_from_string (callee, 
722                                                      strlen (callee),
723                                                      &peer.public_key))
724   {
725     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
726                 _("`%s'  is not a valid public key\n"),
727                 callee);
728     h->notification_handler (NULL, h, NotificationType_NO_PEER, NULL);
729     return;
730   }  
731   initiate_call (h, peer);
732 }
733
734 void
735 GNUNET_CONVERSATION_hangup (struct GNUNET_CONVERSATION_Handle *h)
736 {
737   if (NULL == h || NULL == h->client)
738     return;
739
740   terminate_call (h);
741 }
742
743 void
744 GNUNET_CONVERSATION_accept (struct GNUNET_CONVERSATION_Handle *h)
745 {
746   if (NULL == h || NULL == h->client)
747     return;
748
749   accept_call (h);
750 }
751
752 void
753 GNUNET_CONVERSATION_reject (struct GNUNET_CONVERSATION_Handle *h)
754 {
755   if (NULL == h || NULL == h->client)
756     return;
757
758   reject_call (h);
759 }
760
761 /* end of conversation_api.c */