diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-10-05 13:10:53 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-10-05 13:10:53 +0000 |
commit | ac3a1c494fd48fc1d01fcc4eafa0b3f4878f5441 (patch) | |
tree | a21b54452171f582444a199e70426b4c4266152b /src/conversation/gnunet-conversation.c | |
parent | 45c9ba99503eaf130b3d298062c612e281893d6a (diff) | |
download | gnunet-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.c | 818 |
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 | */ |
37 | static struct GNUNET_CONVERSATION_Handle *conversation; | 35 | #define MAX_MESSAGE_LENGTH 1024 |
36 | |||
37 | |||
38 | /** | ||
39 | * Possible states of the program. | ||
40 | */ | ||
41 | enum 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 | */ | ||
89 | static struct GNUNET_CONVERSATION_Phone *phone; | ||
90 | |||
91 | /** | ||
92 | * Call handle | ||
93 | */ | ||
94 | static struct GNUNET_CONVERSATION_Call *call; | ||
95 | |||
96 | /** | ||
97 | * Desired phone line. | ||
98 | */ | ||
99 | static 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; | |||
42 | static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; | 104 | static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; |
43 | 105 | ||
44 | /** | 106 | /** |
45 | * Function declareation for executing a action | 107 | * Our speaker. |
46 | */ | 108 | */ |
47 | typedef int (*ActionFunction) (const char *argumetns, | 109 | static struct GNUNET_SPEAKER_Handle *speaker; |
48 | const void *xtra); | ||
49 | 110 | ||
50 | /** | 111 | /** |
51 | * Structure which defines a command | 112 | * Our microphone. |
52 | */ | 113 | */ |
53 | struct VoipCommand | 114 | static struct GNUNET_MICROPHONE_Handle *mic; |
54 | { | 115 | |
55 | const char *command; | 116 | /** |
56 | ActionFunction Action; | 117 | * Our configuration. |
57 | const char *helptext; | 118 | */ |
58 | }; | 119 | static struct GNUNET_CONFIGURATION_Handle *cfg; |
59 | 120 | ||
121 | /** | ||
122 | * Our ego. | ||
123 | */ | ||
124 | static struct GNUNET_IDENTITY_Ego *caller_id; | ||
125 | |||
126 | /** | ||
127 | * Handle to identity service. | ||
128 | */ | ||
129 | static struct GNUNET_IDENTITY_Handle *id; | ||
60 | 130 | ||
61 | static int | 131 | /** |
62 | do_help (const char *args, | 132 | * Name of our ego. |
63 | const void *xtra); | 133 | */ |
134 | static char *ego_name; | ||
64 | 135 | ||
136 | /** | ||
137 | * Name of conversation partner (if any). | ||
138 | */ | ||
139 | static char *peer_name; | ||
140 | |||
141 | /** | ||
142 | * File handle for stdin. | ||
143 | */ | ||
144 | static struct GNUNET_DISK_FileHandle *stdin_fh; | ||
145 | |||
146 | /** | ||
147 | * Our current state. | ||
148 | */ | ||
149 | static enum ConversationState state; | ||
65 | 150 | ||
66 | /** | 151 | /** |
67 | * Method called whenever a call is incoming | 152 | * Be verbose. |
153 | */ | ||
154 | static 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 | */ |
73 | static void | 164 | static void |
74 | call_handler (void *cls, | 165 | phone_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 | */ |
92 | static void | 211 | static void |
93 | reject_handler (void *cls, | 212 | start_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 | */ |
112 | static void | 251 | static void |
113 | notification_handler (void *cls, | 252 | call_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 | */ |
161 | static void | 317 | typedef void (*ActionFunction) (const char *arguments); |
162 | missed_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 | */ |
174 | static int | 323 | struct VoipCommand |
175 | do_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 | */ | ||
347 | static void | ||
348 | do_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 | */ |
185 | static int | 356 | static void |
186 | do_unknown (const char *msg, | 357 | do_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 | */ |
199 | static int | 368 | static void |
200 | do_call (const char *arg, | 369 | do_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 | */ |
216 | static int | 382 | static void |
217 | do_call_peer (const char *arg, | 383 | do_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 | */ |
233 | static int | 456 | static void |
234 | do_accept (const char *args, | 457 | do_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 | */ |
248 | static int | 501 | static void |
249 | do_reject (const char *args, | 502 | do_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 | */ |
262 | static int | 551 | static void |
263 | do_hang_up (const char *args, | 552 | do_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 | */ |
276 | static struct VoipCommand commands[] = { | 590 | static 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 | */ |
298 | static int | 614 | static void |
299 | do_help (const char *args, | 615 | do_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 | */ |
342 | static void | 660 | static void |
343 | do_stop_task (void *cls, | 661 | do_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 | */ |
363 | static void | 703 | static void |
364 | handle_command (void *cls, | 704 | handle_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 | ||
390 | next: | 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 | */ | |
399 | out: | 745 | static void |
400 | handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | 746 | identity_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 | ¬ification_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 | |||
449 | main (int argc, char *const *argv) | 827 | main (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 */ |