-fix build system issues
[oweals/gnunet.git] / src / conversation / conversation_api.c
1 /*
2   This file is part of GNUnet
3   (C) 2013 Christian Grothoff (and other contributing authors)
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 3, 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 phone and caller API to the conversation service
24  * @author Simon Dieterle
25  * @author Andreas Fuchs
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_conversation_service.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_gns_service.h"
32 #include "conversation.h"
33
34
35 /**
36  * Possible states of a caller.
37  */
38 enum CallerState
39 {
40   /**
41    * We still need to reverse lookup the caller ID.
42    */
43   CS_RESOLVE,
44
45   /**
46    * The phone is ringing (user knows about incoming call).
47    */
48   CS_RINGING,
49
50   /**
51    * The phone is in an active conversation.
52    */
53   CS_ACTIVE,
54
55   /**
56    * We suspended the conversation.
57    */
58   CS_CALLEE_SUSPENDED,
59
60   /**
61    * Caller suspended the conversation.
62    */
63   CS_CALLER_SUSPENDED,
64
65   /**
66    * Both sides suspended the conversation.
67    */
68   CS_BOTH_SUSPENDED
69 };
70
71
72
73 /**
74  * A caller is the handle we have for an incoming call.
75  */
76 struct GNUNET_CONVERSATION_Caller
77 {
78
79   /**
80    * We keep all callers in a DLL.
81    */
82   struct GNUNET_CONVERSATION_Caller *next;
83
84   /**
85    * We keep all callers in a DLL.
86    */
87   struct GNUNET_CONVERSATION_Caller *prev;
88
89   /**
90    * Our phone.
91    */
92   struct GNUNET_CONVERSATION_Phone *phone;
93
94   /**
95    * Function to call for phone events.
96    */
97   GNUNET_CONVERSATION_CallerEventHandler event_handler;
98
99   /**
100    * Closure for @e event_handler
101    */
102   void *event_handler_cls;
103
104   /**
105    * Speaker, or NULL if none is attached.
106    */
107   struct GNUNET_SPEAKER_Handle *speaker;
108
109   /**
110    * Microphone, or NULL if none is attached.
111    */
112   struct GNUNET_MICROPHONE_Handle *mic;
113
114   /**
115    * Active NAMESTORE lookup (or NULL).
116    */
117   struct GNUNET_NAMESTORE_QueueEntry *qe;
118
119   /**
120    * Identity of the person calling us.
121    */
122   struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
123
124   /**
125    * Caller ID of the person calling us as a string.
126    */
127   char *caller_id_str;
128
129   /**
130    * Internal handle to identify the caller with the service.
131    */
132   uint32_t cid;
133
134   /**
135    * State machine for the phone.
136    */
137   enum CallerState state;
138
139 };
140
141
142 /**
143  * Possible states of a phone.
144  */
145 enum PhoneState
146 {
147   /**
148    * We still need to register the phone.
149    */
150   PS_REGISTER = 0,
151
152   /**
153    * We are waiting for calls.
154    */
155   PS_READY
156
157 };
158
159
160 /**
161  * A phone is a device that can ring to signal an incoming call and
162  * that you can pick up to answer the call and hang up to terminate
163  * the call.  You can also hang up a ringing phone immediately
164  * (without picking it up) to stop it from ringing.  Phones have
165  * caller ID.  You can ask the phone for its record and make that
166  * record available (via GNS) to enable others to call you.
167  * Multiple phones maybe connected to the same line (the line is
168  * something rather internal to a phone and not obvious from it).
169  * You can only have one conversation per phone at any time.
170  */
171 struct GNUNET_CONVERSATION_Phone
172 {
173   /**
174    * Our configuration.
175    */
176   const struct GNUNET_CONFIGURATION_Handle *cfg;
177
178   /**
179    * Handle to talk with CONVERSATION service.
180    */
181   struct GNUNET_CLIENT_Connection *client;
182
183   /**
184    * We keep all callers in a DLL.
185    */
186   struct GNUNET_CONVERSATION_Caller *caller_head;
187
188   /**
189    * We keep all callers in a DLL.
190    */
191   struct GNUNET_CONVERSATION_Caller *caller_tail;
192
193   /**
194    * Function to call for phone events.
195    */
196   GNUNET_CONVERSATION_PhoneEventHandler event_handler;
197
198   /**
199    * Closure for @e event_handler
200    */
201   void *event_handler_cls;
202
203   /**
204    * Connection to NAMESTORE (for reverse lookup).
205    */
206   struct GNUNET_NAMESTORE_Handle *ns;
207
208   /**
209    * Handle for transmitting to the CONVERSATION service.
210    */
211   struct GNUNET_MQ_Handle *mq;
212
213   /**
214    * This phone's record.
215    */
216   struct GNUNET_CONVERSATION_PhoneRecord my_record;
217
218   /**
219    * My GNS zone.
220    */
221   struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
222
223   /**
224    * State machine for the phone.
225    */
226   enum PhoneState state;
227
228 };
229
230
231 /**
232  * The phone got disconnected, reconnect to the service.
233  *
234  * @param phone phone to reconnect
235  */
236 static void
237 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone);
238
239
240 /**
241  * We have resolved the caller ID using our name service.
242  *
243  * @param cls the `struct GNUNET_CONVERSATION_Caller`
244  * @param zone our zone used for resolution
245  * @param label name of the caller
246  * @param rd_count number of records we have in @a rd
247  * @param rd records we have for the caller's label
248  */
249 static void
250 handle_caller_name (void *cls,
251                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
252                     const char *label,
253                     unsigned int rd_count,
254                     const struct GNUNET_GNSRECORD_Data *rd)
255 {
256   struct GNUNET_CONVERSATION_Caller *caller = cls;
257   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
258   char *name;
259
260   caller->qe = NULL;
261   if (NULL == label)
262     name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id));
263   else
264     GNUNET_asprintf (&name, "%s.gnu", label);
265   caller->caller_id_str = name;
266   caller->state = CS_RINGING;
267   phone->event_handler (phone->event_handler_cls,
268                         GNUNET_CONVERSATION_EC_PHONE_RING,
269                         caller,
270                         name);
271 }
272
273
274 /**
275  * Process recorded audio data.
276  *
277  * @param cls closure with the `struct GNUNET_CONVERSATION_Caller`
278  * @param data_size number of bytes in @a data
279  * @param data audio data to play
280  */
281 static void
282 transmit_phone_audio (void *cls,
283                       size_t data_size,
284                       const void *data)
285 {
286   struct GNUNET_CONVERSATION_Caller *caller = cls;
287   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
288   struct GNUNET_MQ_Envelope *e;
289   struct ClientAudioMessage *am;
290
291   e = GNUNET_MQ_msg_extra (am,
292                            data_size,
293                            GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
294   am->cid = caller->cid;
295   memcpy (&am[1], data, data_size);
296   GNUNET_MQ_send (phone->mq, e);
297 }
298
299
300 /**
301  * We received a `struct ClientPhoneRingMessage`
302  *
303  * @param cls the `struct GNUNET_CONVERSATION_Phone`
304  * @param msg the message
305  */
306 static void
307 handle_phone_ring (void *cls,
308                    const struct GNUNET_MessageHeader *msg)
309 {
310   struct GNUNET_CONVERSATION_Phone *phone = cls;
311   const struct ClientPhoneRingMessage *ring;
312   struct GNUNET_CONVERSATION_Caller *caller;
313
314   ring = (const struct ClientPhoneRingMessage *) msg;
315   switch (phone->state)
316   {
317   case PS_REGISTER:
318     GNUNET_assert (0);
319     break;
320   case PS_READY:
321     caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller);
322     caller->phone = phone;
323     GNUNET_CONTAINER_DLL_insert (phone->caller_head,
324                                  phone->caller_tail,
325                                  caller);
326     caller->state = CS_RESOLVE;
327     caller->caller_id = ring->caller_id;
328     caller->cid = ring->cid;
329     caller->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns,
330                                                 &phone->my_zone,
331                                                 &ring->caller_id,
332                                                 &handle_caller_name,
333                                                 caller);
334     break;
335   }
336 }
337
338
339 /**
340  * We received a `struct ClientPhoneHangupMessage`.
341  *
342  * @param cls the `struct GNUNET_CONVERSATION_Phone`
343  * @param msg the message
344  */
345 static void
346 handle_phone_hangup (void *cls,
347                      const struct GNUNET_MessageHeader *msg)
348 {
349   struct GNUNET_CONVERSATION_Phone *phone = cls;
350   const struct ClientPhoneHangupMessage *hang;
351   struct GNUNET_CONVERSATION_Caller *caller;
352
353   hang = (const struct ClientPhoneHangupMessage *) msg;
354   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
355     if (hang->cid == caller->cid)
356       break;
357   if (NULL == caller)
358   {
359     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360                 "Received HANG_UP message for unknown caller ID %u\n",
361                 (unsigned int) hang->cid);
362     return;
363   }
364
365   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366               "Received HANG_UP message, terminating call with `%s'\n",
367               caller->caller_id_str);
368   switch (caller->state)
369   {
370   case CS_RESOLVE:
371     /* application doesn't even know about call yet */
372     GNUNET_NAMESTORE_cancel (caller->qe);
373     caller->qe = NULL;
374     break;
375   case CS_RINGING:
376     phone->event_handler (phone->event_handler_cls,
377                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
378                           caller,
379                           caller->caller_id_str);
380     break;
381   case CS_ACTIVE:
382     caller->speaker->disable_speaker (caller->speaker->cls);
383     caller->mic->disable_microphone (caller->mic->cls);
384     phone->event_handler (phone->event_handler_cls,
385                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
386                           caller,
387                           caller->caller_id_str);
388     break;
389   case CS_CALLEE_SUSPENDED:
390   case CS_CALLER_SUSPENDED:
391   case CS_BOTH_SUSPENDED:
392     phone->event_handler (phone->event_handler_cls,
393                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
394                           caller,
395                           caller->caller_id_str);
396     break;
397   }
398   GNUNET_CONTAINER_DLL_remove (phone->caller_head,
399                                phone->caller_tail,
400                                caller);
401   GNUNET_free (caller);
402 }
403
404
405 /**
406  * We received a `struct ClientPhoneSuspendMessage`.
407  *
408  * @param cls the `struct GNUNET_CONVERSATION_Phone`
409  * @param msg the message
410  */
411 static void
412 handle_phone_suspend (void *cls,
413                      const struct GNUNET_MessageHeader *msg)
414 {
415   struct GNUNET_CONVERSATION_Phone *phone = cls;
416   struct GNUNET_CONVERSATION_Caller *caller;
417   const struct ClientPhoneSuspendMessage *suspend;
418
419   suspend = (const struct ClientPhoneSuspendMessage *) msg;
420   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
421     if (suspend->cid == caller->cid)
422       break;
423   if (NULL == caller)
424     return;
425   switch (caller->state)
426   {
427   case CS_RESOLVE:
428     GNUNET_break_op (0);
429     break;
430   case CS_RINGING:
431     GNUNET_break_op (0);
432     break;
433   case CS_ACTIVE:
434     caller->state = CS_CALLER_SUSPENDED;
435     caller->speaker->disable_speaker (caller->speaker->cls);
436     caller->mic->disable_microphone (caller->mic->cls);
437     caller->event_handler (caller->event_handler_cls,
438                            GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
439     break;
440   case CS_CALLEE_SUSPENDED:
441     caller->state = CS_BOTH_SUSPENDED;
442     caller->event_handler (caller->event_handler_cls,
443                            GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
444     break;
445   case CS_CALLER_SUSPENDED:
446   case CS_BOTH_SUSPENDED:
447     GNUNET_break_op (0);
448     break;
449   }
450 }
451
452
453 /**
454  * We received a `struct ClientPhoneResumeMessage`.
455  *
456  * @param cls the `struct GNUNET_CONVERSATION_Phone`
457  * @param msg the message
458  */
459 static void
460 handle_phone_resume (void *cls,
461                      const struct GNUNET_MessageHeader *msg)
462 {
463   struct GNUNET_CONVERSATION_Phone *phone = cls;
464   struct GNUNET_CONVERSATION_Caller *caller;
465   const struct ClientPhoneResumeMessage *resume;
466
467   resume = (const struct ClientPhoneResumeMessage *) msg;
468   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
469     if (resume->cid == caller->cid)
470       break;
471   if (NULL == caller)
472     return;
473   switch (caller->state)
474   {
475   case CS_RESOLVE:
476     GNUNET_break_op (0);
477     break;
478   case CS_RINGING:
479     GNUNET_break_op (0);
480     break;
481   case CS_ACTIVE:
482   case CS_CALLEE_SUSPENDED:
483     GNUNET_break_op (0);
484     break;
485   case CS_CALLER_SUSPENDED:
486     caller->state = CS_ACTIVE;
487     caller->speaker->enable_speaker (caller->speaker->cls);
488     caller->mic->enable_microphone (caller->mic->cls,
489                                     &transmit_phone_audio,
490                                     caller);
491     caller->event_handler (caller->event_handler_cls,
492                            GNUNET_CONVERSATION_EC_CALLER_RESUME);
493     break;
494   case CS_BOTH_SUSPENDED:
495     caller->state = CS_CALLEE_SUSPENDED;
496     caller->event_handler (caller->event_handler_cls,
497                            GNUNET_CONVERSATION_EC_CALLER_RESUME);
498     break;
499   }
500 }
501
502
503 /**
504  * We received a `struct ClientAudioMessage`
505  *
506  * @param cls the `struct GNUNET_CONVERSATION_Phone`
507  * @param msg the message
508  */
509 static void
510 handle_phone_audio_message (void *cls,
511                             const struct GNUNET_MessageHeader *msg)
512 {
513   struct GNUNET_CONVERSATION_Phone *phone = cls;
514   const struct ClientAudioMessage *am;
515   struct GNUNET_CONVERSATION_Caller *caller;
516
517   am = (const struct ClientAudioMessage *) msg;
518   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
519     if (am->cid == caller->cid)
520       break;
521   if (NULL == caller)
522     return;
523   switch (caller->state)
524   {
525   case CS_RESOLVE:
526     GNUNET_break_op (0);
527     break;
528   case CS_RINGING:
529     GNUNET_break_op (0);
530     break;
531   case CS_ACTIVE:
532     caller->speaker->play (caller->speaker->cls,
533                            ntohs (msg->size) - sizeof (struct ClientAudioMessage),
534                            &am[1]);
535     break;
536   case CS_CALLEE_SUSPENDED:
537   case CS_CALLER_SUSPENDED:
538   case CS_BOTH_SUSPENDED:
539     break;
540   }
541 }
542
543
544 /**
545  * We encountered an error talking with the conversation service.
546  *
547  * @param cls the `struct GNUNET_CONVERSATION_Phone`
548  * @param error details about the error
549  */
550 static void
551 phone_error_handler (void *cls,
552                      enum GNUNET_MQ_Error error)
553 {
554   struct GNUNET_CONVERSATION_Phone *phone = cls;
555
556   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
557               _("Connection to conversation service lost, trying to reconnect\n"));
558   reconnect_phone (phone);
559 }
560
561
562 /**
563  * Clean up all callers of the given phone.
564  *
565  * @param phone phone to clean up callers for
566  */
567 static void
568 clean_up_callers (struct GNUNET_CONVERSATION_Phone *phone)
569 {
570   struct GNUNET_CONVERSATION_Caller *caller;
571
572   while (NULL != (caller = phone->caller_head))
573   {
574     /* make sure mic/speaker are disabled *before* callback */
575     if (CS_ACTIVE == caller->state)
576     {
577       caller->speaker->disable_speaker (caller->speaker->cls);
578       caller->mic->disable_microphone (caller->mic->cls);
579       caller->state = CS_CALLER_SUSPENDED;
580     }
581     phone->event_handler (phone->event_handler_cls,
582                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
583                           caller,
584                           caller->caller_id_str);
585     GNUNET_CONVERSATION_caller_hang_up (caller);
586   }
587 }
588
589
590 /**
591  * The phone got disconnected, reconnect to the service.
592  *
593  * @param phone phone to reconnect
594  */
595 static void
596 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone)
597 {
598   static struct GNUNET_MQ_MessageHandler handlers[] =
599   {
600     { &handle_phone_ring,
601       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING,
602       sizeof (struct ClientPhoneRingMessage) },
603     { &handle_phone_hangup,
604       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
605       sizeof (struct ClientPhoneHangupMessage) },
606     { &handle_phone_suspend,
607       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
608       sizeof (struct ClientPhoneSuspendMessage) },
609     { &handle_phone_resume,
610       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
611       sizeof (struct ClientPhoneResumeMessage) },
612     { &handle_phone_audio_message,
613       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
614       0 },
615     { NULL, 0, 0 }
616   };
617   struct GNUNET_MQ_Envelope *e;
618   struct ClientPhoneRegisterMessage *reg;
619
620   clean_up_callers (phone);
621   if (NULL != phone->mq)
622   {
623     GNUNET_MQ_destroy (phone->mq);
624     phone->mq = NULL;
625   }
626   if (NULL != phone->client)
627   {
628     GNUNET_CLIENT_disconnect (phone->client);
629     phone->client = NULL;
630   }
631   phone->state = PS_REGISTER;
632   phone->client = GNUNET_CLIENT_connect ("conversation", phone->cfg);
633   if (NULL == phone->client)
634     return;
635   phone->mq = GNUNET_MQ_queue_for_connection_client (phone->client,
636                                                      handlers,
637                                                      &phone_error_handler,
638                                                      phone);
639   e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
640   reg->line = phone->my_record.line;
641   GNUNET_MQ_send (phone->mq, e);
642   phone->state = PS_READY;
643 }
644
645
646 /**
647  * Create a new phone.
648  *
649  * @param cfg configuration for the phone; specifies the phone service and
650  *        which line the phone is to be connected to
651  * @param ego ego to use for name resolution (when determining caller ID)
652  * @param event_handler how to notify the owner of the phone about events
653  * @param event_handler_cls closure for @a event_handler
654  * @return NULL on error (no valid line configured)
655  */
656 struct GNUNET_CONVERSATION_Phone *
657 GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
658                                   const struct GNUNET_IDENTITY_Ego *ego,
659                                   GNUNET_CONVERSATION_PhoneEventHandler event_handler,
660                                   void *event_handler_cls)
661 {
662   struct GNUNET_CONVERSATION_Phone *phone;
663   unsigned long long line;
664
665   if (GNUNET_OK !=
666       GNUNET_CONFIGURATION_get_value_number (cfg,
667                                              "CONVERSATION",
668                                              "LINE",
669                                              &line))
670     return NULL;
671   if (line >= (1 << 31))
672     return NULL;
673   phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
674   if (GNUNET_OK !=
675       GNUNET_CRYPTO_get_peer_identity (cfg,
676                                        &phone->my_record.peer))
677   {
678     GNUNET_break (0);
679     GNUNET_free (phone);
680     return NULL;
681   }
682   phone->cfg = cfg;
683   phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
684   phone->event_handler = event_handler;
685   phone->event_handler_cls = event_handler_cls;
686   phone->ns = GNUNET_NAMESTORE_connect (cfg);
687   phone->my_record.line = htonl ((uint32_t) line);
688   phone->my_record.version = htonl (0);
689   reconnect_phone (phone);
690   if ( (NULL == phone->client) ||
691        (NULL == phone->ns) )
692   {
693     GNUNET_break (0);
694     GNUNET_CONVERSATION_phone_destroy (phone);
695     return NULL;
696   }
697   return phone;
698 }
699
700
701 /**
702  * Fill in a namestore record with the contact information
703  * for this phone.  Note that the filled in "data" value
704  * is only valid until the phone is destroyed.
705  *
706  * @param phone phone to create a record for
707  * @param rd namestore record to fill in
708  */
709 void
710 GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
711                                       struct GNUNET_GNSRECORD_Data *rd)
712 {
713   rd->data = &phone->my_record;
714   rd->expiration_time = 0;
715   rd->data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
716   rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE;
717   rd->flags = GNUNET_GNSRECORD_RF_NONE;
718 }
719
720
721 /**
722  * Picks up a (ringing) phone.  This will connect the speaker
723  * to the microphone of the other party, and vice versa.
724  *
725  * @param caller handle that identifies which caller should be answered
726  * @param event_handler how to notify about events by the caller
727  * @param event_handler_cls closure for @a event_handler
728  * @param speaker speaker to use
729  * @param mic microphone to use
730  */
731 void
732 GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
733                                     GNUNET_CONVERSATION_CallerEventHandler event_handler,
734                                     void *event_handler_cls,
735                                     struct GNUNET_SPEAKER_Handle *speaker,
736                                     struct GNUNET_MICROPHONE_Handle *mic)
737 {
738   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
739   struct GNUNET_MQ_Envelope *e;
740   struct ClientPhonePickupMessage *pick;
741
742   GNUNET_assert (CS_RINGING == caller->state);
743   caller->speaker = speaker;
744   caller->mic = mic;
745   e = GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
746   pick->cid = caller->cid;
747   GNUNET_MQ_send (phone->mq, e);
748   caller->state = CS_ACTIVE;
749   caller->event_handler = event_handler;
750   caller->event_handler_cls = event_handler_cls;
751   caller->speaker->enable_speaker (caller->speaker->cls);
752   caller->mic->enable_microphone (caller->mic->cls,
753                                   &transmit_phone_audio,
754                                   caller);
755 }
756
757
758 /**
759  * Hang up up a (possibly ringing) phone.  This will notify the other
760  * party that we are no longer interested in talking with them.
761  *
762  * @param caller conversation to hang up on
763  */
764 void
765 GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller)
766 {
767   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
768   struct GNUNET_MQ_Envelope *e;
769   struct ClientPhoneHangupMessage *hang;
770
771   switch (caller->state)
772   {
773   case CS_RESOLVE:
774     GNUNET_NAMESTORE_cancel (caller->qe);
775     caller->qe = NULL;
776     break;
777   case CS_ACTIVE:
778     caller->speaker->disable_speaker (caller->speaker->cls);
779     caller->mic->disable_microphone (caller->mic->cls);
780     break;
781   default:
782     break;
783   }
784   GNUNET_CONTAINER_DLL_remove (phone->caller_head,
785                                phone->caller_tail,
786                                caller);
787   GNUNET_free_non_null (caller->caller_id_str);
788   GNUNET_free (caller);
789   e = GNUNET_MQ_msg (hang,
790                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
791   GNUNET_MQ_send (phone->mq, e);
792 }
793
794
795 /**
796  * Destroys a phone.
797  *
798  * @param phone phone to destroy
799  */
800 void
801 GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
802 {
803   clean_up_callers (phone);
804   if (NULL != phone->ns)
805   {
806     GNUNET_NAMESTORE_disconnect (phone->ns);
807     phone->ns = NULL;
808   }
809   if (NULL != phone->mq)
810   {
811     GNUNET_MQ_destroy (phone->mq);
812     phone->mq = NULL;
813   }
814   if (NULL != phone->client)
815   {
816     GNUNET_CLIENT_disconnect (phone->client);
817     phone->client = NULL;
818   }
819   GNUNET_free (phone);
820 }
821
822
823 /**
824  * Pause conversation of an active call.  This will disconnect the speaker
825  * and the microphone.  The call can later be resumed with
826  * #GNUNET_CONVERSATION_caller_resume.
827  *
828  * @param caller call to suspend
829  */
830 void
831 GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller)
832 {
833   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
834   struct GNUNET_MQ_Envelope *e;
835   struct ClientPhoneSuspendMessage *suspend;
836
837   GNUNET_assert ( (CS_ACTIVE == caller->state) ||
838                   (CS_CALLER_SUSPENDED == caller->state) );
839   if (CS_ACTIVE == caller->state)
840   {
841     caller->speaker->disable_speaker (caller->speaker->cls);
842     caller->mic->disable_microphone (caller->mic->cls);
843   }
844   caller->speaker = NULL;
845   caller->mic = NULL;
846   e = GNUNET_MQ_msg (suspend, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
847   suspend->cid = caller->cid;
848   GNUNET_MQ_send (phone->mq, e);
849   if (CS_ACTIVE == caller->state)
850     caller->state = CS_CALLEE_SUSPENDED;
851   else
852     caller->state = CS_BOTH_SUSPENDED;
853 }
854
855
856 /**
857  * Resume suspended conversation of a phone.
858  *
859  * @param caller call to resume
860  * @param speaker speaker to use
861  * @param mic microphone to use
862  */
863 void
864 GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
865                                    struct GNUNET_SPEAKER_Handle *speaker,
866                                    struct GNUNET_MICROPHONE_Handle *mic)
867 {
868   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
869   struct GNUNET_MQ_Envelope *e;
870   struct ClientPhoneResumeMessage *resume;
871
872   GNUNET_assert ( (CS_CALLEE_SUSPENDED == caller->state) ||
873                   (CS_BOTH_SUSPENDED == caller->state) );
874   caller->speaker = speaker;
875   caller->mic = mic;
876   e = GNUNET_MQ_msg (resume, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
877   resume->cid = caller->cid;
878   GNUNET_MQ_send (phone->mq, e);
879   if (CS_CALLEE_SUSPENDED == caller->state)
880   {
881     caller->state = CS_ACTIVE;
882     caller->speaker->enable_speaker (caller->speaker->cls);
883     caller->mic->enable_microphone (caller->mic->cls,
884                                     &transmit_phone_audio,
885                                     caller);
886   }
887   else
888   {
889     caller->state = CS_CALLER_SUSPENDED;
890   }
891 }
892
893 /* end of conversation_api.c */