aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-conversation.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-05 13:10:53 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-05 13:10:53 +0000
commitac3a1c494fd48fc1d01fcc4eafa0b3f4878f5441 (patch)
treea21b54452171f582444a199e70426b4c4266152b /src/conversation/gnunet-conversation.c
parent45c9ba99503eaf130b3d298062c612e281893d6a (diff)
downloadgnunet-ac3a1c494fd48fc1d01fcc4eafa0b3f4878f5441.tar.gz
gnunet-ac3a1c494fd48fc1d01fcc4eafa0b3f4878f5441.zip
-rename fest: new to default
Diffstat (limited to 'src/conversation/gnunet-conversation.c')
-rw-r--r--src/conversation/gnunet-conversation.c818
1 files changed, 600 insertions, 218 deletions
diff --git a/src/conversation/gnunet-conversation.c b/src/conversation/gnunet-conversation.c
index a4088984b..fdf6155fd 100644
--- a/src/conversation/gnunet-conversation.c
+++ b/src/conversation/gnunet-conversation.c
@@ -14,7 +14,7 @@
14 14
15 You should have received a copy of the GNU General Public License 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 16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, InGNUNET_SERVERc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19*/ 19*/
20/** 20/**
@@ -27,14 +27,76 @@
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h" 28#include "gnunet_constants.h"
29#include "gnunet_conversation_service.h" 29#include "gnunet_conversation_service.h"
30#include <fcntl.h>
31 30
32#define MAX_MESSAGE_LENGTH (32 * 1024)
33 31
34/** 32/**
35 * CONVERSATION handle 33 * Maximum length allowed for the command line input.
36 */ 34 */
37static struct GNUNET_CONVERSATION_Handle *conversation; 35#define MAX_MESSAGE_LENGTH 1024
36
37
38/**
39 * Possible states of the program.
40 */
41enum ConversationState
42{
43 /**
44 * We're waiting for our own idenitty.
45 */
46 CS_LOOKUP_EGO,
47
48 /**
49 * We're listening for calls
50 */
51 CS_LISTEN,
52
53 /**
54 * Our phone is ringing.
55 */
56 CS_RING,
57
58 /**
59 * We accepted an incoming phone call.
60 */
61 CS_ACCEPTED,
62
63 /**
64 * We are looking up some other participant.
65 */
66 CS_RESOLVING,
67
68 /**
69 * We are now ringing the other participant.
70 */
71 CS_RINGING,
72
73 /**
74 * The other party accepted our call and we are now connected.
75 */
76 CS_CONNECTED,
77
78 /**
79 * Internal error
80 */
81 CS_ERROR
82
83};
84
85
86/**
87 * Phone handle
88 */
89static struct GNUNET_CONVERSATION_Phone *phone;
90
91/**
92 * Call handle
93 */
94static struct GNUNET_CONVERSATION_Call *call;
95
96/**
97 * Desired phone line.
98 */
99static unsigned int line;
38 100
39/** 101/**
40 * Task which handles the commands 102 * Task which handles the commands
@@ -42,231 +104,483 @@ static struct GNUNET_CONVERSATION_Handle *conversation;
42static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; 104static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task;
43 105
44/** 106/**
45 * Function declareation for executing a action 107 * Our speaker.
46 */ 108 */
47typedef int (*ActionFunction) (const char *argumetns, 109static struct GNUNET_SPEAKER_Handle *speaker;
48 const void *xtra);
49 110
50/** 111/**
51* Structure which defines a command 112 * Our microphone.
52*/ 113 */
53struct VoipCommand 114static struct GNUNET_MICROPHONE_Handle *mic;
54{ 115
55 const char *command; 116/**
56 ActionFunction Action; 117 * Our configuration.
57 const char *helptext; 118 */
58}; 119static struct GNUNET_CONFIGURATION_Handle *cfg;
59 120
121/**
122 * Our ego.
123 */
124static struct GNUNET_IDENTITY_Ego *caller_id;
125
126/**
127 * Handle to identity service.
128 */
129static struct GNUNET_IDENTITY_Handle *id;
60 130
61static int 131/**
62do_help (const char *args, 132 * Name of our ego.
63 const void *xtra); 133 */
134static char *ego_name;
64 135
136/**
137 * Name of conversation partner (if any).
138 */
139static char *peer_name;
140
141/**
142 * File handle for stdin.
143 */
144static struct GNUNET_DISK_FileHandle *stdin_fh;
145
146/**
147 * Our current state.
148 */
149static enum ConversationState state;
65 150
66/** 151/**
67 * Method called whenever a call is incoming 152 * Be verbose.
153 */
154static int verbose;
155
156
157/**
158 * Function called with an event emitted by a phone.
68 * 159 *
69 * @param cls closure 160 * @param cls closure
70 * @param handle to the conversation session 161 * @param code type of the event on the phone
71 * @param caller peer that calls you 162 * @param ... additional information, depends on @a code
72 */ 163 */
73static void 164static void
74call_handler (void *cls, 165phone_event_handler (void *cls,
75 struct GNUNET_CONVERSATION_Handle *handle, 166 enum GNUNET_CONVERSATION_EventCode code,
76 const struct GNUNET_PeerIdentity *caller) 167 ...)
77{ 168{
78 FPRINTF (stdout, 169 va_list va;
79 _("Incoming call from peer: %s\n"), 170
80 GNUNET_i2s_full (caller)); 171 va_start (va, code);
172 switch (code)
173 {
174 case GNUNET_CONVERSATION_EC_RING:
175 GNUNET_break (CS_LISTEN == state);
176 GNUNET_free_non_null (peer_name);
177 peer_name = GNUNET_strdup (va_arg (va, const char *));
178 FPRINTF (stdout,
179 _("Incoming call from `%s'.\nPlease /accept or /cancel the call.\n"),
180 peer_name);
181 state = CS_RING;
182 break;
183 case GNUNET_CONVERSATION_EC_RINGING:
184 GNUNET_break (0);
185 break;
186 case GNUNET_CONVERSATION_EC_READY:
187 GNUNET_break (0);
188 break;
189 case GNUNET_CONVERSATION_EC_GNS_FAIL:
190 GNUNET_break (0);
191 break;
192 case GNUNET_CONVERSATION_EC_BUSY:
193 GNUNET_break (0);
194 break;
195 case GNUNET_CONVERSATION_EC_TERMINATED:
196 GNUNET_break ( (CS_RING == state) ||
197 (CS_ACCEPTED == state) );
198 FPRINTF (stdout,
199 _("Call terminated: %s\n"),
200 va_arg (va, const char *));
201 state = CS_LISTEN;
202 break;
203 }
204 va_end (va);
81} 205}
82 206
83 207
84/** 208/**
85 * Method called whenever a call is rejected 209 * Start our phone.
86 *
87 * @param cls closure
88 * @param handle to the conversation session
89 * @param reason given reason why the call was rejected
90 * @param peer peer that rejected your call
91 */ 210 */
92static void 211static void
93reject_handler (void *cls, 212start_phone ()
94 struct GNUNET_CONVERSATION_Handle *handle,
95 enum GNUNET_CONVERSATION_RejectReason reason,
96 const struct GNUNET_PeerIdentity *peer)
97{ 213{
98 FPRINTF (stdout, 214 if (NULL == caller_id)
99 _("Peer %s rejected your call. Reason: %d\n"), 215 {
100 GNUNET_i2s_full (peer), reason); 216 FPRINTF (stderr,
217 _("Ego `%s' no longer available, phone is now down.\n"),
218 ego_name);
219 state = CS_LOOKUP_EGO;
220 return;
221 }
222 phone = GNUNET_CONVERSATION_phone_create (cfg,
223 caller_id,
224 &phone_event_handler, NULL);
225 /* FIXME: get record and print full GNS record info later here... */
226 if (NULL == phone)
227 {
228 FPRINTF (stderr,
229 "%s",
230 _("Failed to setup phone (internal error)\n"));
231 state = CS_ERROR;
232 }
233 else
234 {
235 if (verbose)
236 FPRINTF (stdout,
237 _("Phone active on line %u\n"),
238 (unsigned int) line);
239 state = CS_LISTEN;
240 }
101} 241}
102 242
103 243
104/** 244/**
105 * Method called whenever a notification is there 245 * Function called with an event emitted by a phone.
106 * 246 *
107 * @param cls closure 247 * @param cls closure
108 * @param handle to the conversation session 248 * @param code type of the event on the phone
109 * @param type the type of the notification 249 * @param ... additional information, depends on @a code
110 * @param peer peer that the notification is about
111 */ 250 */
112static void 251static void
113notification_handler (void *cls, 252call_event_handler (void *cls,
114 struct GNUNET_CONVERSATION_Handle *handle, 253 enum GNUNET_CONVERSATION_EventCode code,
115 enum GNUNET_CONVERSATION_NotificationType type, 254 ...)
116 const struct GNUNET_PeerIdentity *peer)
117{ 255{
118 switch (type) 256 va_list va;
257
258 va_start (va, code);
259 switch (code)
119 { 260 {
120 case GNUNET_CONVERSATION_NT_SERVICE_BLOCKED: 261 case GNUNET_CONVERSATION_EC_RING:
262 GNUNET_break (0);
263 break;
264 case GNUNET_CONVERSATION_EC_RINGING:
265 GNUNET_break (CS_RESOLVING == state);
266 if (verbose)
267 FPRINTF (stdout,
268 "%s",
269 _("Resolved address. Now ringing other party.\n"));
270 state = CS_RINGING;
271 break;
272 case GNUNET_CONVERSATION_EC_READY:
273 GNUNET_break (CS_RINGING == state);
121 FPRINTF (stdout, 274 FPRINTF (stdout,
122 _("The service is already in use. Try again later.")); 275 _("Connection established: %s\n"),
123 break; 276 va_arg (va, const char *));
124 case GNUNET_CONVERSATION_NT_NO_PEER: 277 state = CS_CONNECTED;
125 FPRINTF (stdout, 278 break;
126 _("The Peer you were calling is no correct peer.\n")); 279 case GNUNET_CONVERSATION_EC_GNS_FAIL:
127 break; 280 GNUNET_break (CS_RESOLVING == state);
128 case GNUNET_CONVERSATION_NT_NO_ANSWER:
129 FPRINTF (stdout,
130 _("Peer %s did not answer your call.\n"),
131 GNUNET_i2s_full (peer));
132 break;
133 case GNUNET_CONVERSATION_NT_AVAILABLE_AGAIN:
134 FPRINTF (stdout, 281 FPRINTF (stdout,
135 _("Peer %s is now available.\n"), 282 "%s",
136 GNUNET_i2s_full (peer)); 283 _("Failed to resolve name\n"));
137 break; 284 GNUNET_CONVERSATION_call_stop (call, NULL);
138 case GNUNET_CONVERSATION_NT_CALL_ACCEPTED: 285 call = NULL;
139 FPRINTF (stdout, 286 start_phone ();
140 _("Peer %s has accepted your call.\n"), 287 break;
141 GNUNET_i2s_full (peer)); 288 case GNUNET_CONVERSATION_EC_BUSY:
142 break; 289 GNUNET_break (CS_RINGING == state);
143 case GNUNET_CONVERSATION_NT_CALL_TERMINATED:
144 FPRINTF (stdout, 290 FPRINTF (stdout,
145 _("Peer %s has terminated the call.\n"), 291 "%s",
146 GNUNET_i2s_full (peer)); 292 _("Line busy\n"));
293 GNUNET_CONVERSATION_call_stop (call, NULL);
294 call = NULL;
295 start_phone ();
147 break; 296 break;
148 default: 297 case GNUNET_CONVERSATION_EC_TERMINATED:
149 GNUNET_break (0); 298 GNUNET_break ( (CS_RINGING == state) ||
150 } 299 (CS_CONNECTED == state) );
300 FPRINTF (stdout,
301 _("Call terminated: %s\n"),
302 va_arg (va, const char *));
303 GNUNET_CONVERSATION_call_stop (call, NULL);
304 call = NULL;
305 start_phone ();
306 break;
307 }
308 va_end (va);
151} 309}
152 310
153 311
154/** 312/**
155 * Method called whenever a notification for missed calls is there 313 * Function declareation for executing a action
156 * 314 *
157 * @param cls closure 315 * @param arguments arguments given to the function
158 * @param handle to the conversation session
159 * @param missed_calls a list of missed calls
160 */ 316 */
161static void 317typedef void (*ActionFunction) (const char *arguments);
162missed_call_handler (void *cls,
163 struct GNUNET_CONVERSATION_Handle *handle,
164 struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls)
165{
166 FPRINTF (stdout,
167 _("You have missed calls.\n"));
168}
169 318
170 319
171/** 320/**
172 * Terminating the client 321 * Structure which defines a command
173 */ 322 */
174static int 323struct VoipCommand
175do_quit (const char *args,
176 const void *xtra)
177{ 324{
178 return GNUNET_SYSERR; 325 /**
179} 326 * Command the user needs to enter.
327 */
328 const char *command;
329
330 /**
331 * Function to call on command.
332 */
333 ActionFunction Action;
334
335 /**
336 * Help text for the command.
337 */
338 const char *helptext;
339};
340
341
342/**
343 * Action function to print help for the command shell.
344 *
345 * @param arguments arguments given to the command
346 */
347static void
348do_help (const char *args);
180 349
181 350
182/** 351/**
352 * Terminate the client
183 * 353 *
354 * @param args arguments given to the command
184 */ 355 */
185static int 356static void
186do_unknown (const char *msg, 357do_quit (const char *args)
187 const void *xtra)
188{ 358{
189 FPRINTF (stderr, 359 GNUNET_SCHEDULER_shutdown ();
190 _("Unknown command `%s'\n"),
191 msg);
192 return GNUNET_OK;
193} 360}
194 361
195 362
196/** 363/**
197 * Initiating a new call 364 * Handler for unknown command.
365 *
366 * @param args arguments given to the command
198 */ 367 */
199static int 368static void
200do_call (const char *arg, 369do_unknown (const char *msg)
201 const void *xtra)
202{ 370{
203 FPRINTF (stdout, 371 FPRINTF (stderr,
204 _("Initiating call to: %s\n"), 372 _("Unknown command `%s'\n"),
205 arg); 373 msg);
206 GNUNET_CONVERSATION_call (conversation,
207 arg,
208 GNUNET_YES);
209 return GNUNET_OK;
210} 374}
211 375
212 376
213/** 377/**
214 * Initiating a new call 378 * Initiating a new call
379 *
380 * @param args arguments given to the command
215 */ 381 */
216static int 382static void
217do_call_peer (const char *arg, 383do_call (const char *arg)
218 const void *xtra)
219{ 384{
220 FPRINTF (stdout, 385 if (NULL == caller_id)
221 _("Initiating call to: %s\n"), 386 {
222 arg); 387 FPRINTF (stderr,
223 GNUNET_CONVERSATION_call (conversation, 388 _("Ego `%s' not available\n"),
224 arg, 389 ego_name);
225 GNUNET_NO); 390 return;
226 return GNUNET_OK; 391 }
392 switch (state)
393 {
394 case CS_LOOKUP_EGO:
395 FPRINTF (stderr,
396 _("Ego `%s' not available\n"),
397 ego_name);
398 return;
399 case CS_LISTEN:
400 /* ok to call! */
401 break;
402 case CS_RING:
403 FPRINTF (stdout,
404 _("Hanging up on incoming phone call from `%s' to call `%s'.\n"),
405 peer_name,
406 arg);
407 GNUNET_CONVERSATION_phone_hang_up (phone, NULL);
408 break;
409 case CS_ACCEPTED:
410 FPRINTF (stderr,
411 _("You are already in a conversation with `%s', refusing to call `%s'.\n"),
412 peer_name,
413 arg);
414 return;
415 case CS_RESOLVING:
416 case CS_RINGING:
417 FPRINTF (stderr,
418 _("Aborting call to `%s'\n"),
419 peer_name);
420 GNUNET_CONVERSATION_call_stop (call, NULL);
421 call = NULL;
422 break;
423 case CS_CONNECTED:
424 FPRINTF (stderr,
425 _("You are already in a conversation with `%s', refusing to call `%s'.\n"),
426 peer_name,
427 arg);
428 return;
429 case CS_ERROR:
430 /* ok to call */
431 break;
432 }
433 GNUNET_assert (NULL == call);
434 if (NULL != phone)
435 {
436 GNUNET_CONVERSATION_phone_destroy (phone);
437 phone = NULL;
438 }
439 GNUNET_free_non_null (peer_name);
440 peer_name = GNUNET_strdup (arg);
441 call = GNUNET_CONVERSATION_call_start (cfg,
442 caller_id,
443 arg,
444 speaker,
445 mic,
446 &call_event_handler, NULL);
447 state = CS_RESOLVING;
227} 448}
228 449
229 450
230/** 451/**
231 * Accepting an incoming call 452 * Accepting an incoming call
453 *
454 * @param args arguments given to the command
232 */ 455 */
233static int 456static void
234do_accept (const char *args, 457do_accept (const char *args)
235 const void *xtra)
236{ 458{
237 FPRINTF (stdout, 459 switch (state)
238 _("Accepting the call\n")); 460 {
239 GNUNET_CONVERSATION_accept (conversation); 461 case CS_LOOKUP_EGO:
240 462 case CS_LISTEN:
241 return GNUNET_OK; 463 case CS_ERROR:
464 FPRINTF (stderr,
465 _("There is no incoming call to be accepted!\n"));
466 return;
467 case CS_RING:
468 /* this is the expected state */
469 break;
470 case CS_ACCEPTED:
471 FPRINTF (stderr,
472 _("You are already in a conversation with `%s'.\n"),
473 peer_name);
474 return;
475 case CS_RESOLVING:
476 case CS_RINGING:
477 FPRINTF (stderr,
478 _("You are trying to call `%s', cannot accept incoming calls right now.\n"),
479 peer_name);
480 return;
481 case CS_CONNECTED:
482 FPRINTF (stderr,
483 _("You are already in a conversation with `%s'.\n"),
484 peer_name);
485 return;
486 }
487 GNUNET_assert (NULL != phone);
488 GNUNET_CONVERSATION_phone_pick_up (phone,
489 args,
490 speaker,
491 mic);
492 state = CS_ACCEPTED;
242} 493}
243 494
244 495
245/** 496/**
246 * Rejecting a call 497 * Accepting an incoming call
498 *
499 * @param args arguments given to the command
247 */ 500 */
248static int 501static void
249do_reject (const char *args, 502do_status (const char *args)
250 const void *xtra)
251{ 503{
252 FPRINTF (stdout, 504 switch (state)
253 _("Rejecting the call\n")); 505 {
254 GNUNET_CONVERSATION_reject (conversation); 506 case CS_LOOKUP_EGO:
255 return GNUNET_OK; 507 FPRINTF (stdout,
508 _("We are currently trying to locate the private key for the ego `%s'.\n"),
509 ego_name);
510 break;
511 case CS_LISTEN:
512 FPRINTF (stdout,
513 _("We are listening for incoming calls for ego `%s' on line %u.\n"),
514 ego_name,
515 line);
516 break;
517 case CS_RING:
518 FPRINTF (stdout,
519 _("The phone is rining. `%s' is trying to call us.\n"),
520 peer_name);
521 break;
522 case CS_ACCEPTED:
523 case CS_CONNECTED:
524 FPRINTF (stdout,
525 _("You are having a conversation with `%s'.\n"),
526 peer_name);
527 break;
528 case CS_RESOLVING:
529 FPRINTF (stdout,
530 _("We are trying to find the network address to call `%s'.\n"),
531 peer_name);
532 break;
533 case CS_RINGING:
534 FPRINTF (stdout,
535 _("We are calling `%s', his phone should be ringing.\n"),
536 peer_name);
537 break;
538 case CS_ERROR:
539 FPRINTF (stdout,
540 _("We had an internal error setting up our phone line. You can still make calls.\n"));
541 break;
542 }
256} 543}
257 544
258 545
259/** 546/**
260 * Terminating a call 547 * Rejecting a call
548 *
549 * @param args arguments given to the command
261 */ 550 */
262static int 551static void
263do_hang_up (const char *args, 552do_reject (const char *args)
264 const void *xtra)
265{ 553{
266 FPRINTF (stdout, 554 switch (state)
267 _("Terminating the call\n")); 555 {
268 GNUNET_CONVERSATION_hangup (conversation); 556 case CS_LOOKUP_EGO:
269 return GNUNET_OK; 557 case CS_LISTEN:
558 case CS_ERROR:
559 FPRINTF (stderr,
560 "%s",
561 _("There is no call that could be cancelled right now.\n"));
562 return;
563 case CS_RING:
564 case CS_ACCEPTED:
565 case CS_RESOLVING:
566 case CS_RINGING:
567 case CS_CONNECTED:
568 /* expected state, do rejection logic */
569 break;
570 }
571 if (NULL == call)
572 {
573 GNUNET_assert (NULL != phone);
574 GNUNET_CONVERSATION_phone_hang_up (phone,
575 args);
576 state = CS_LISTEN;
577 }
578 else
579 {
580 GNUNET_CONVERSATION_call_stop (call, args);
581 call = NULL;
582 start_phone ();
583 }
270} 584}
271 585
272 586
@@ -274,36 +588,38 @@ do_hang_up (const char *args,
274 * List of supported commands. 588 * List of supported commands.
275 */ 589 */
276static struct VoipCommand commands[] = { 590static struct VoipCommand commands[] = {
277 {"/call ", &do_call, gettext_noop ("Use `/call gns_name'")}, 591 {"/call", &do_call,
278 {"/callpeer ", &do_call_peer, 592 gettext_noop ("Use `/call USER.gnu'")},
279 gettext_noop ("Use `/call private_key' to call a person")},
280 {"/accept", &do_accept, 593 {"/accept", &do_accept,
281 gettext_noop ("Use `/accept' to accept an incoming call")}, 594 gettext_noop ("Use `/accept MESSAGE' to accept an incoming call")},
282 {"/terminate", &do_hang_up, 595 {"/cancel", &do_reject,
283 gettext_noop ("Use `/terminate' to end a call")}, 596 gettext_noop ("Use `/cancel MESSAGE' to reject or terminate a call")},
284 {"/reject", &do_reject, 597 {"/status", &do_status,
285 gettext_noop ("Use `/rejet' to reject an incoming call")}, 598 gettext_noop ("Use `/status to print status information")},
286 {"/quit", &do_quit, gettext_noop ("Use `/quit' to terminate gnunet-conversation")}, 599 {"/quit", &do_quit,
600 gettext_noop ("Use `/quit' to terminate gnunet-conversation")},
287 {"/help", &do_help, 601 {"/help", &do_help,
288 gettext_noop ("Use `/help command' to get help for a specific command")}, 602 gettext_noop ("Use `/help command' to get help for a specific command")},
289 {"/", &do_unknown, NULL}, 603 {"", &do_unknown,
290 {"", &do_unknown, NULL}, 604 NULL},
291 {NULL, NULL, NULL}, 605 {NULL, NULL, NULL},
292}; 606};
293 607
294 608
295/** 609/**
610 * Action function to print help for the command shell.
296 * 611 *
612 * @param arguments arguments given to the command
297 */ 613 */
298static int 614static void
299do_help (const char *args, 615do_help (const char *args)
300 const void *xtra)
301{ 616{
302 int i; 617 unsigned int i;
303 618
304 i = 0; 619 i = 0;
305 while ((NULL != args) && (0 != strlen (args)) && 620 while ( (NULL != args) &&
306 (commands[i].Action != &do_help)) 621 (0 != strlen (args)) &&
622 (commands[i].Action != &do_help))
307 { 623 {
308 if (0 == 624 if (0 ==
309 strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) 625 strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1))
@@ -311,18 +627,18 @@ do_help (const char *args,
311 FPRINTF (stdout, 627 FPRINTF (stdout,
312 "%s\n", 628 "%s\n",
313 gettext (commands[i].helptext)); 629 gettext (commands[i].helptext));
314 return GNUNET_OK; 630 return;
315 } 631 }
316 i++; 632 i++;
317 } 633 }
318 i = 0; 634 i = 0;
319 FPRINTF (stdout, 635 FPRINTF (stdout,
320 "%s", 636 "%s",
321 "Available commands:"); 637 "Available commands:\n");
322 while (commands[i].Action != &do_help) 638 while (commands[i].Action != &do_help)
323 { 639 {
324 FPRINTF (stdout, 640 FPRINTF (stdout,
325 " %s", 641 "%s\n",
326 gettext (commands[i].command)); 642 gettext (commands[i].command));
327 i++; 643 i++;
328 } 644 }
@@ -332,73 +648,136 @@ do_help (const char *args,
332 FPRINTF (stdout, 648 FPRINTF (stdout,
333 "%s\n", 649 "%s\n",
334 gettext (commands[i].helptext)); 650 gettext (commands[i].helptext));
335 return GNUNET_OK;
336} 651}
337 652
338 653
339/** 654/**
655 * Task run during shutdown.
340 * 656 *
657 * @param cls NULL
658 * @param tc unused
341 */ 659 */
342static void 660static void
343do_stop_task (void *cls, 661do_stop_task (void *cls,
344 const struct GNUNET_SCHEDULER_TaskContext *tc) 662 const struct GNUNET_SCHEDULER_TaskContext *tc)
345{ 663{
346 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 664 if (NULL != call)
347 "Running shutdown task\n"); 665 {
348 GNUNET_CONVERSATION_disconnect (conversation); 666 GNUNET_CONVERSATION_call_stop (call, NULL);
349 667 call = NULL;
350 if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) 668 }
669 if (NULL != phone)
670 {
671 GNUNET_CONVERSATION_phone_destroy (phone);
672 phone = NULL;
673 }
674 if (GNUNET_SCHEDULER_NO_TASK != handle_cmd_task)
351 { 675 {
352 GNUNET_SCHEDULER_cancel (handle_cmd_task); 676 GNUNET_SCHEDULER_cancel (handle_cmd_task);
353 handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; 677 handle_cmd_task = GNUNET_SCHEDULER_NO_TASK;
354 } 678 }
355 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 679 if (NULL != id)
356 "Running shutdown task finished\n"); 680 {
681 GNUNET_IDENTITY_disconnect (id);
682 id = NULL;
683 }
684 GNUNET_SPEAKER_destroy (speaker);
685 speaker = NULL;
686 GNUNET_MICROPHONE_destroy (mic);
687 mic = NULL;
688 GNUNET_free (ego_name);
689 ego_name = NULL;
690 GNUNET_CONFIGURATION_destroy (cfg);
691 cfg = NULL;
692 GNUNET_free_non_null (peer_name);
693 state = CS_ERROR;
357} 694}
358 695
359 696
360/** 697/**
698 * Task to handle commands from the terminal.
361 * 699 *
700 * @param cls NULL
701 * @param tc scheduler context
362 */ 702 */
363static void 703static void
364handle_command (void *cls, 704handle_command (void *cls,
365 const struct GNUNET_SCHEDULER_TaskContext *tc) 705 const struct GNUNET_SCHEDULER_TaskContext *tc)
366{ 706{
367 char message[MAX_MESSAGE_LENGTH + 1]; 707 char message[MAX_MESSAGE_LENGTH + 1];
368 int i; 708 const char *ptr;
709 size_t i;
369 710
711 handle_cmd_task =
712 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
713 stdin_fh,
714 &handle_command, NULL);
370 /* read message from command line and handle it */ 715 /* read message from command line and handle it */
371 memset (message, 0, MAX_MESSAGE_LENGTH + 1); 716 memset (message, 0, MAX_MESSAGE_LENGTH + 1);
372 if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) 717 if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin))
373 goto next; 718 return;
374 if (strlen (message) == 0) 719 if (0 == strlen (message))
375 goto next; 720 return;
376 if (message[strlen (message) - 1] == '\n') 721 if (message[strlen (message) - 1] == '\n')
377 message[strlen (message) - 1] = '\0'; 722 message[strlen (message) - 1] = '\0';
378 if (strlen (message) == 0) 723 if (0 == strlen (message))
379 goto next; 724 return;
380 i = 0; 725 i = 0;
381 while ((NULL != commands[i].command) && 726 while ((NULL != commands[i].command) &&
382 (0 != 727 (0 != strncasecmp (commands[i].command, message,
383 strncasecmp (commands[i].command, message, 728 strlen (commands[i].command))))
384 strlen (commands[i].command))))
385 i++; 729 i++;
386 if (GNUNET_OK != 730 ptr = &message[strlen (commands[i].command)];
387 commands[i].Action (&message[strlen (commands[i].command)], NULL)) 731 while (isspace ((int) *ptr))
388 goto out; 732 ptr++;
733 commands[i].Action (ptr);
734}
389 735
390next: 736
391 handle_cmd_task = 737/**
392 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply 738 * Function called by identity service with information about egos.
393 (GNUNET_TIME_UNIT_MILLISECONDS, 739 *
394 100), 740 * @param cls NULL
395 GNUNET_SCHEDULER_PRIORITY_UI, 741 * @param ego ego handle
396 &handle_command, NULL); 742 * @param ctx unused
397 return; 743 * @param name name of the ego
398 744 */
399out: 745static void
400 handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; 746identity_cb (void *cls,
401 GNUNET_SCHEDULER_shutdown (); 747 struct GNUNET_IDENTITY_Ego *ego,
748 void **ctx,
749 const char *name)
750{
751 if (NULL == name)
752 return;
753 if (ego == caller_id)
754 {
755 if (verbose)
756 FPRINTF (stdout,
757 _("Name of our ego changed to `%s'\n"),
758 name);
759 GNUNET_free (ego_name);
760 ego_name = GNUNET_strdup (name);
761 return;
762 }
763 if (0 != strcmp (name,
764 ego_name))
765 return;
766 if (NULL == ego)
767 {
768 if (verbose)
769 FPRINTF (stdout,
770 _("Our ego `%s' was deleted!\n"),
771 ego_name);
772 caller_id = NULL;
773 return;
774 }
775 caller_id = ego;
776 GNUNET_CONFIGURATION_set_value_number (cfg,
777 "CONVERSATION",
778 "LINE",
779 line);
780 start_phone ();
402} 781}
403 782
404 783
@@ -416,20 +795,19 @@ run (void *cls,
416 const char *cfgfile, 795 const char *cfgfile,
417 const struct GNUNET_CONFIGURATION_Handle *c) 796 const struct GNUNET_CONFIGURATION_Handle *c)
418{ 797{
419 if (NULL == 798 cfg = GNUNET_CONFIGURATION_dup (c);
420 (conversation = 799 speaker = GNUNET_SPEAKER_create_from_hardware (cfg);
421 GNUNET_CONVERSATION_connect (c, NULL, 800 mic = GNUNET_MICROPHONE_create_from_hardware (cfg);
422 &call_handler, 801 if (NULL == ego_name)
423 &reject_handler,
424 &notification_handler,
425 &missed_call_handler)))
426 { 802 {
427 FPRINTF (stderr, 803 FPRINTF (stderr,
428 "%s", 804 "%s",
429 _("Could not access CONVERSATION service. Exiting.\n")); 805 _("You must specify the NAME of an ego to use\n"));
430 return; 806 return;
431 } 807 }
432 808 id = GNUNET_IDENTITY_connect (cfg,
809 &identity_cb,
810 NULL);
433 handle_cmd_task = 811 handle_cmd_task =
434 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, 812 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
435 &handle_command, NULL); 813 &handle_command, NULL);
@@ -449,25 +827,29 @@ int
449main (int argc, char *const *argv) 827main (int argc, char *const *argv)
450{ 828{
451 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 829 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
830 {'e', "ego", "NAME",
831 gettext_noop ("sets the NAME of the ego to use for the phone (and name resolution)"),
832 1, &GNUNET_GETOPT_set_string, &ego_name},
833 {'p', "phone", "LINE",
834 gettext_noop ("sets the LINE to use for the phone"),
835 1, &GNUNET_GETOPT_set_uint, &line},
452 GNUNET_GETOPT_OPTION_END 836 GNUNET_GETOPT_OPTION_END
453 }; 837 };
454
455 int flags; 838 int flags;
456 int ret; 839 int ret;
457 840
458 flags = fcntl (0, F_GETFL, 0); 841 flags = fcntl (0, F_GETFL, 0);
459 flags |= O_NONBLOCK; 842 flags |= O_NONBLOCK;
460 fcntl (0, F_SETFL, flags); 843 fcntl (0, F_SETFL, flags);
461 844 stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0);
462 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 845 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
463 return 2; 846 return 2;
464 847 ret = GNUNET_PROGRAM_run (argc, argv,
465 ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-conversation", 848 "gnunet-conversation",
466 gettext_noop ("Print information about conversation."), 849 gettext_noop ("Enables having a conversation with other GNUnet users."),
467 options, &run, NULL); 850 options, &run, NULL);
468 GNUNET_free ((void *) argv); 851 GNUNET_free ((void *) argv);
469 852 return (GNUNET_OK == ret) ? 0 : 1;
470 return ret;
471} 853}
472 854
473/* end of gnunet-conversation.c */ 855/* end of gnunet-conversation.c */