diff options
Diffstat (limited to 'src/chat/gnunet-chat.c')
-rw-r--r-- | src/chat/gnunet-chat.c | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/src/chat/gnunet-chat.c b/src/chat/gnunet-chat.c new file mode 100644 index 000000000..b960db043 --- /dev/null +++ b/src/chat/gnunet-chat.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2007, 2008, 2011 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 chat/gnunet-chat.c | ||
23 | * @brief Minimal chat command line tool | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * @author Vitaly Minko | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_getopt_lib.h" | ||
31 | #include "gnunet_program_lib.h" | ||
32 | #include "gnunet_chat_service.h" | ||
33 | #include <fcntl.h> | ||
34 | |||
35 | static int ret; | ||
36 | |||
37 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
38 | |||
39 | static char *nickname; | ||
40 | |||
41 | static char *room_name; | ||
42 | |||
43 | static struct GNUNET_CONTAINER_MetaData *meta; | ||
44 | |||
45 | static struct GNUNET_CHAT_Room *room; | ||
46 | |||
47 | static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | ||
48 | |||
49 | struct ChatCommand | ||
50 | { | ||
51 | const char *command; | ||
52 | int (*Action) (const char *arguments, const void *xtra); | ||
53 | const char *helptext; | ||
54 | }; | ||
55 | |||
56 | struct UserList | ||
57 | { | ||
58 | struct UserList *next; | ||
59 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; | ||
60 | int ignored; | ||
61 | }; | ||
62 | |||
63 | static struct UserList *users; | ||
64 | |||
65 | static void | ||
66 | free_user_list () | ||
67 | { | ||
68 | struct UserList *next; | ||
69 | while (NULL != users) | ||
70 | { | ||
71 | next = users->next; | ||
72 | GNUNET_free (users); | ||
73 | users = next; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static int do_help (const char *args, const void *xtra); | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Callback used for notification about incoming messages. | ||
82 | * | ||
83 | * @param cls closure, NULL | ||
84 | * @param room in which room was the message received? | ||
85 | * @param sender what is the ID of the sender? (maybe NULL) | ||
86 | * @param member_info information about the joining member | ||
87 | * @param message the message text | ||
88 | * @param options options for the message | ||
89 | * @return GNUNET_OK to accept the message now, GNUNET_NO to | ||
90 | * accept (but user is away), GNUNET_SYSERR to signal denied delivery | ||
91 | */ | ||
92 | static int | ||
93 | receive_cb (void *cls, | ||
94 | struct GNUNET_CHAT_Room *room, | ||
95 | const GNUNET_HashCode *sender, | ||
96 | const struct GNUNET_CONTAINER_MetaData *meta, | ||
97 | const char *message, | ||
98 | enum GNUNET_CHAT_MsgOptions options) | ||
99 | { | ||
100 | char *nick; | ||
101 | const char *fmt; | ||
102 | |||
103 | if (NULL != sender) | ||
104 | nick = GNUNET_PSEUDONYM_id_to_name (cfg, sender); | ||
105 | else | ||
106 | nick = GNUNET_strdup (_("anonymous")); | ||
107 | fmt = NULL; | ||
108 | switch (options) | ||
109 | { | ||
110 | case GNUNET_CHAT_MSG_OPTION_NONE: | ||
111 | case GNUNET_CHAT_MSG_ANONYMOUS: | ||
112 | fmt = _("`%s' said: %s\n"); | ||
113 | break; | ||
114 | case GNUNET_CHAT_MSG_PRIVATE: | ||
115 | fmt = _("`%s' said to you: %s\n"); | ||
116 | break; | ||
117 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: | ||
118 | fmt = _("`%s' said to you: %s\n"); | ||
119 | break; | ||
120 | case GNUNET_CHAT_MSG_AUTHENTICATED: | ||
121 | fmt = _("`%s' said for sure: %s\n"); | ||
122 | break; | ||
123 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: | ||
124 | fmt = _("`%s' said to you for sure: %s\n"); | ||
125 | break; | ||
126 | case GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
127 | fmt = _("`%s' was confirmed that you received: %s\n"); | ||
128 | break; | ||
129 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
130 | fmt = _("`%s' was confirmed that you and only you received: %s\n"); | ||
131 | break; | ||
132 | case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
133 | fmt = _("`%s' was confirmed that you received from him or her: %s\n"); | ||
134 | break; | ||
135 | case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
136 | fmt = | ||
137 | _ | ||
138 | ("`%s' was confirmed that you and only you received from him or her: %s\n"); | ||
139 | break; | ||
140 | case GNUNET_CHAT_MSG_OFF_THE_RECORD: | ||
141 | fmt = _("`%s' said off the record: %s\n"); | ||
142 | break; | ||
143 | default: | ||
144 | fmt = _("<%s> said using an unknown message type: %s\n"); | ||
145 | break; | ||
146 | } | ||
147 | fprintf (stdout, fmt, nick, message); | ||
148 | GNUNET_free (nick); | ||
149 | return GNUNET_OK; | ||
150 | } | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Callback used for message delivery confirmations. | ||
155 | * | ||
156 | * @param cls closure, NULL | ||
157 | * @param room in which room was the message received? | ||
158 | * @param orig_seq_number sequence number of the original message | ||
159 | * @param timestamp when was the message received? | ||
160 | * @param receiver who is confirming the receipt? | ||
161 | * @param msg_hash hash of the original message | ||
162 | * @param receipt signature confirming delivery | ||
163 | * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further | ||
164 | * confirmations from anyone for this message | ||
165 | */ | ||
166 | static int | ||
167 | confirmation_cb (void *cls, | ||
168 | struct GNUNET_CHAT_Room *room, | ||
169 | uint32_t orig_seq_number, | ||
170 | struct GNUNET_TIME_Absolute timestamp, | ||
171 | const GNUNET_HashCode *receiver, | ||
172 | const GNUNET_HashCode *msg_hash, | ||
173 | const struct GNUNET_CRYPTO_RsaSignature *receipt) | ||
174 | { | ||
175 | char *nick; | ||
176 | |||
177 | nick = GNUNET_PSEUDONYM_id_to_name (cfg, receiver); | ||
178 | fprintf (stdout, _("'%s' acknowledged message #%d\n"), nick, orig_seq_number); | ||
179 | return GNUNET_OK; | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Callback used for notification that another room member has joined or left. | ||
185 | * | ||
186 | * @param member_info will be non-null if the member is joining, NULL if he is | ||
187 | * leaving | ||
188 | * @param member_id hash of public key of the user (for unique identification) | ||
189 | * @param options what types of messages is this member willing to receive? | ||
190 | * @return GNUNET_OK | ||
191 | */ | ||
192 | static int | ||
193 | member_list_cb (void *cls, | ||
194 | const struct GNUNET_CONTAINER_MetaData *member_info, | ||
195 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, | ||
196 | enum GNUNET_CHAT_MsgOptions options) | ||
197 | { | ||
198 | char *nick; | ||
199 | GNUNET_HashCode id; | ||
200 | struct UserList *pos; | ||
201 | struct UserList *prev; | ||
202 | |||
203 | GNUNET_CRYPTO_hash (member_id, | ||
204 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
205 | &id); | ||
206 | nick = GNUNET_PSEUDONYM_id_to_name (cfg, &id); | ||
207 | fprintf (stdout, member_info != NULL | ||
208 | ? _("`%s' entered the room\n") : _("`%s' left the room\n"), nick); | ||
209 | GNUNET_free (nick); | ||
210 | if (NULL != member_info) | ||
211 | { | ||
212 | /* user joining */ | ||
213 | pos = GNUNET_malloc (sizeof (struct UserList)); | ||
214 | pos->next = users; | ||
215 | pos->pkey = *member_id; | ||
216 | pos->ignored = GNUNET_NO; | ||
217 | users = pos; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | /* user leaving */ | ||
222 | prev = NULL; | ||
223 | pos = users; | ||
224 | while ((NULL != pos) && | ||
225 | (0 != memcmp (&pos->pkey, | ||
226 | member_id, | ||
227 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) | ||
228 | { | ||
229 | prev = pos; | ||
230 | pos = pos->next; | ||
231 | } | ||
232 | if (NULL == pos) | ||
233 | { | ||
234 | GNUNET_break (0); | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | if (NULL == prev) | ||
239 | users = pos->next; | ||
240 | else | ||
241 | prev->next = pos->next; | ||
242 | GNUNET_free (pos); | ||
243 | } | ||
244 | } | ||
245 | return GNUNET_OK; | ||
246 | } | ||
247 | |||
248 | |||
249 | static int | ||
250 | do_transmit (const char *msg, const void *xtra) | ||
251 | { | ||
252 | uint32_t seq; | ||
253 | GNUNET_CHAT_send_message (room, | ||
254 | msg, | ||
255 | GNUNET_CHAT_MSG_OPTION_NONE, | ||
256 | NULL, &seq); | ||
257 | return GNUNET_OK; | ||
258 | } | ||
259 | |||
260 | |||
261 | static int | ||
262 | do_join (const char *arg, const void *xtra) | ||
263 | { | ||
264 | char *my_name; | ||
265 | GNUNET_HashCode me; | ||
266 | |||
267 | if (arg[0] == '#') | ||
268 | arg++; /* ignore first hash */ | ||
269 | GNUNET_CHAT_leave_room (room); | ||
270 | free_user_list (); | ||
271 | GNUNET_free (room_name); | ||
272 | room_name = GNUNET_strdup (arg); | ||
273 | room = GNUNET_CHAT_join_room (cfg, | ||
274 | nickname, | ||
275 | meta, | ||
276 | room_name, | ||
277 | -1, | ||
278 | &receive_cb, NULL, | ||
279 | &member_list_cb, NULL, | ||
280 | &confirmation_cb, NULL, &me); | ||
281 | if (NULL == room) | ||
282 | { | ||
283 | fprintf (stdout, _("Could not change username\n")); | ||
284 | return GNUNET_SYSERR; | ||
285 | } | ||
286 | my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); | ||
287 | fprintf (stdout, _("Joined room `%s' as user `%s'\n"), room_name, my_name); | ||
288 | GNUNET_free (my_name); | ||
289 | return GNUNET_OK; | ||
290 | } | ||
291 | |||
292 | |||
293 | static int | ||
294 | do_nick (const char *msg, const void *xtra) | ||
295 | { | ||
296 | char *my_name; | ||
297 | GNUNET_HashCode me; | ||
298 | |||
299 | GNUNET_CHAT_leave_room (room); | ||
300 | free_user_list (); | ||
301 | GNUNET_free (nickname); | ||
302 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
303 | nickname = GNUNET_strdup (msg); | ||
304 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
305 | GNUNET_CONTAINER_meta_data_insert (meta, | ||
306 | "<gnunet>", | ||
307 | EXTRACTOR_METATYPE_TITLE, | ||
308 | EXTRACTOR_METAFORMAT_UTF8, | ||
309 | "text/plain", | ||
310 | nickname, | ||
311 | strlen(nickname)+1); | ||
312 | room = GNUNET_CHAT_join_room (cfg, | ||
313 | nickname, | ||
314 | meta, | ||
315 | room_name, | ||
316 | -1, | ||
317 | &receive_cb, NULL, | ||
318 | &member_list_cb, NULL, | ||
319 | &confirmation_cb, NULL, &me); | ||
320 | if (NULL == room) | ||
321 | { | ||
322 | fprintf (stdout, _("Could not change username\n")); | ||
323 | return GNUNET_SYSERR; | ||
324 | } | ||
325 | my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); | ||
326 | fprintf (stdout, _("Changed username to `%s'\n"), my_name); | ||
327 | GNUNET_free (my_name); | ||
328 | return GNUNET_OK; | ||
329 | } | ||
330 | |||
331 | |||
332 | static int | ||
333 | do_names (const char *msg, const void *xtra) | ||
334 | { | ||
335 | char *name; | ||
336 | struct UserList *pos; | ||
337 | GNUNET_HashCode pid; | ||
338 | |||
339 | fprintf (stdout, _("Users in room `%s': "), room_name); | ||
340 | pos = users; | ||
341 | while (NULL != pos) | ||
342 | { | ||
343 | GNUNET_CRYPTO_hash (&pos->pkey, | ||
344 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
345 | &pid); | ||
346 | name = GNUNET_PSEUDONYM_id_to_name (cfg, &pid); | ||
347 | fprintf (stdout, "`%s' ", name); | ||
348 | GNUNET_free (name); | ||
349 | pos = pos->next; | ||
350 | } | ||
351 | fprintf (stdout, "\n"); | ||
352 | return GNUNET_OK; | ||
353 | } | ||
354 | |||
355 | |||
356 | static int | ||
357 | do_pm (const char *msg, const void *xtra) | ||
358 | { | ||
359 | char *user; | ||
360 | GNUNET_HashCode uid; | ||
361 | GNUNET_HashCode pid; | ||
362 | uint32_t seq; | ||
363 | struct UserList *pos; | ||
364 | |||
365 | if (NULL == strstr (msg, " ")) | ||
366 | { | ||
367 | fprintf (stderr, _("Syntax: /msg USERNAME MESSAGE")); | ||
368 | return GNUNET_OK; | ||
369 | } | ||
370 | user = GNUNET_strdup (msg); | ||
371 | strstr (user, " ")[0] = '\0'; | ||
372 | msg += strlen (user) + 1; | ||
373 | if (GNUNET_OK != GNUNET_PSEUDONYM_name_to_id (cfg, user, &uid)) | ||
374 | { | ||
375 | fprintf (stderr, _("Unknown user `%s'\n"), user); | ||
376 | GNUNET_free (user); | ||
377 | return GNUNET_OK; | ||
378 | } | ||
379 | pos = users; | ||
380 | while (NULL != pos) | ||
381 | { | ||
382 | GNUNET_CRYPTO_hash (&pos->pkey, | ||
383 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
384 | &pid); | ||
385 | if (0 == memcmp (&pid, &uid, sizeof (GNUNET_HashCode))) | ||
386 | break; | ||
387 | pos = pos->next; | ||
388 | } | ||
389 | if (NULL == pos) | ||
390 | { | ||
391 | fprintf (stderr, _("User `%s' is currently not in the room!\n"), user); | ||
392 | GNUNET_free (user); | ||
393 | return GNUNET_OK; | ||
394 | } | ||
395 | GNUNET_CHAT_send_message (room, | ||
396 | msg, | ||
397 | GNUNET_CHAT_MSG_PRIVATE, | ||
398 | &pos->pkey, | ||
399 | &seq); | ||
400 | GNUNET_free (user); | ||
401 | return GNUNET_OK; | ||
402 | } | ||
403 | |||
404 | |||
405 | static int | ||
406 | do_transmit_sig (const char *msg, const void *xtra) | ||
407 | { | ||
408 | uint32_t seq; | ||
409 | GNUNET_CHAT_send_message (room, | ||
410 | msg, | ||
411 | GNUNET_CHAT_MSG_AUTHENTICATED, | ||
412 | NULL, &seq); | ||
413 | return GNUNET_OK; | ||
414 | } | ||
415 | |||
416 | |||
417 | static int | ||
418 | do_transmit_ack (const char *msg, const void *xtra) | ||
419 | { | ||
420 | uint32_t seq; | ||
421 | GNUNET_CHAT_send_message (room, | ||
422 | msg, | ||
423 | GNUNET_CHAT_MSG_ACKNOWLEDGED, | ||
424 | NULL, &seq); | ||
425 | return GNUNET_OK; | ||
426 | } | ||
427 | |||
428 | |||
429 | static int | ||
430 | do_quit (const char *args, const void *xtra) | ||
431 | { | ||
432 | return GNUNET_SYSERR; | ||
433 | } | ||
434 | |||
435 | |||
436 | static int | ||
437 | do_unknown (const char *msg, const void *xtra) | ||
438 | { | ||
439 | fprintf (stderr, _("Unknown command `%s'\n"), msg); | ||
440 | return GNUNET_OK; | ||
441 | } | ||
442 | |||
443 | |||
444 | /** | ||
445 | * List of supported IRC commands. The order matters! | ||
446 | */ | ||
447 | static struct ChatCommand commands[] = { | ||
448 | {"/join ", &do_join, | ||
449 | gettext_noop | ||
450 | ("Use `/join #roomname' to join a chat room. Joining a room will cause you" | ||
451 | " to leave the current room")}, | ||
452 | {"/nick ", &do_nick, | ||
453 | gettext_noop | ||
454 | ("Use `/nick nickname' to change your nickname. This will cause you to" | ||
455 | " leave the current room and immediately rejoin it with the new name.")}, | ||
456 | {"/msg ", &do_pm, | ||
457 | gettext_noop | ||
458 | ("Use `/msg nickname message' to send a private message to the specified" | ||
459 | " user")}, | ||
460 | {"/notice ", &do_pm, | ||
461 | gettext_noop ("The `/notice' command is an alias for `/msg'")}, | ||
462 | {"/query ", &do_pm, | ||
463 | gettext_noop ("The `/query' command is an alias for `/msg'")}, | ||
464 | {"/sig ", &do_transmit_sig, | ||
465 | gettext_noop ("Use `/sig message' to send a signed public message")}, | ||
466 | {"/ack ", &do_transmit_ack, | ||
467 | gettext_noop | ||
468 | ("Use `/ack message' to require signed acknowledgment of the message")}, | ||
469 | {"/quit", &do_quit, | ||
470 | gettext_noop ("Use `/quit' to terminate gnunet-chat")}, | ||
471 | {"/leave", &do_quit, | ||
472 | gettext_noop ("The `/leave' command is an alias for `/quit'")}, | ||
473 | {"/names", &do_names, | ||
474 | gettext_noop | ||
475 | ("Use `/names' to list all of the current members in the chat room")}, | ||
476 | {"/help", &do_help, | ||
477 | gettext_noop ("Use `/help command' to get help for a specific command")}, | ||
478 | /* Add standard commands: | ||
479 | /whois (print metadata), | ||
480 | /ignore (set flag, check on receive!) */ | ||
481 | /* Add special commands (currently supported): | ||
482 | + anonymous msgs | ||
483 | + authenticated msgs | ||
484 | */ | ||
485 | /* the following three commands must be last! */ | ||
486 | {"/", &do_unknown, NULL}, | ||
487 | {"", &do_transmit, NULL}, | ||
488 | {NULL, NULL, NULL}, | ||
489 | }; | ||
490 | |||
491 | |||
492 | static int | ||
493 | do_help (const char *args, const void *xtra) | ||
494 | { | ||
495 | int i; | ||
496 | i = 0; | ||
497 | while ((NULL != args) && | ||
498 | (0 != strlen (args)) && (commands[i].Action != &do_help)) | ||
499 | { | ||
500 | if (0 == | ||
501 | strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) | ||
502 | { | ||
503 | fprintf (stdout, "%s\n", gettext (commands[i].helptext)); | ||
504 | return GNUNET_OK; | ||
505 | } | ||
506 | i++; | ||
507 | } | ||
508 | i = 0; | ||
509 | fprintf (stdout, "Available commands:"); | ||
510 | while (commands[i].Action != &do_help) | ||
511 | { | ||
512 | fprintf (stdout, " %s", gettext (commands[i].command)); | ||
513 | i++; | ||
514 | } | ||
515 | fprintf (stdout, "\n"); | ||
516 | fprintf (stdout, "%s\n", gettext (commands[i].helptext)); | ||
517 | return GNUNET_OK; | ||
518 | } | ||
519 | |||
520 | |||
521 | static void | ||
522 | do_stop_task (void *cls, | ||
523 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
524 | { | ||
525 | GNUNET_CHAT_leave_room (room); | ||
526 | if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) | ||
527 | { | ||
528 | GNUNET_SCHEDULER_cancel (handle_cmd_task); | ||
529 | handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | ||
530 | } | ||
531 | free_user_list (); | ||
532 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
533 | GNUNET_free (room_name); | ||
534 | GNUNET_free (nickname); | ||
535 | } | ||
536 | |||
537 | |||
538 | void | ||
539 | handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
540 | { | ||
541 | char message[MAX_MESSAGE_LENGTH + 1]; | ||
542 | int i; | ||
543 | |||
544 | /* read message from command line and handle it */ | ||
545 | memset (message, 0, MAX_MESSAGE_LENGTH + 1); | ||
546 | if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) | ||
547 | goto next; | ||
548 | if (strlen (message) == 0) | ||
549 | goto next; | ||
550 | if (message[strlen (message) - 1] == '\n') | ||
551 | message[strlen (message) - 1] = '\0'; | ||
552 | if (strlen (message) == 0) | ||
553 | goto next; | ||
554 | i = 0; | ||
555 | while ((NULL != commands[i].command) && | ||
556 | (0 != strncasecmp (commands[i].command, | ||
557 | message, strlen (commands[i].command)))) | ||
558 | i++; | ||
559 | if (GNUNET_OK != | ||
560 | commands[i].Action (&message[strlen (commands[i].command)], NULL)) | ||
561 | goto out; | ||
562 | |||
563 | next: | ||
564 | handle_cmd_task = | ||
565 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | ||
566 | 100), | ||
567 | &handle_command, | ||
568 | NULL); | ||
569 | return; | ||
570 | |||
571 | out: | ||
572 | handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | ||
573 | GNUNET_SCHEDULER_shutdown (); | ||
574 | } | ||
575 | |||
576 | |||
577 | /** | ||
578 | * Main function that will be run by the scheduler. | ||
579 | * | ||
580 | * @param cls closure, NULL | ||
581 | * @param args remaining command-line arguments | ||
582 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
583 | * @param cfg configuration | ||
584 | */ | ||
585 | static void | ||
586 | run (void *cls, | ||
587 | char *const *args, | ||
588 | const char *cfgfile, | ||
589 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
590 | { | ||
591 | GNUNET_HashCode me; | ||
592 | char *my_name; | ||
593 | |||
594 | cfg = c; | ||
595 | /* check arguments */ | ||
596 | if (NULL == nickname) | ||
597 | { | ||
598 | fprintf (stderr, _("You must specify a nickname\n")); | ||
599 | ret = -1; | ||
600 | return; | ||
601 | } | ||
602 | if (NULL == room_name) | ||
603 | room_name = GNUNET_strdup ("gnunet"); | ||
604 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
605 | GNUNET_CONTAINER_meta_data_insert (meta, | ||
606 | "<gnunet>", | ||
607 | EXTRACTOR_METATYPE_TITLE, | ||
608 | EXTRACTOR_METAFORMAT_UTF8, | ||
609 | "text/plain", | ||
610 | nickname, | ||
611 | strlen(nickname)+1); | ||
612 | room = GNUNET_CHAT_join_room (cfg, | ||
613 | nickname, | ||
614 | meta, | ||
615 | room_name, | ||
616 | -1, | ||
617 | &receive_cb, NULL, | ||
618 | &member_list_cb, NULL, | ||
619 | &confirmation_cb, NULL, &me); | ||
620 | if (NULL == room) | ||
621 | { | ||
622 | fprintf (stderr, _("Failed to join room `%s'\n"), room_name); | ||
623 | GNUNET_free (room_name); | ||
624 | GNUNET_free (nickname); | ||
625 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
626 | ret = -1; | ||
627 | return; | ||
628 | } | ||
629 | my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); | ||
630 | fprintf (stdout, _("Joined room `%s' as user `%s'\n"), room_name, my_name); | ||
631 | GNUNET_free (my_name); | ||
632 | handle_cmd_task = | ||
633 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, | ||
634 | &handle_command, | ||
635 | NULL); | ||
636 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
637 | &do_stop_task, | ||
638 | NULL); | ||
639 | } | ||
640 | |||
641 | |||
642 | /** | ||
643 | * The main function to chat via GNUnet. | ||
644 | * | ||
645 | * @param argc number of arguments from the command line | ||
646 | * @param argv command line arguments | ||
647 | * @return 0 ok, 1 on error | ||
648 | */ | ||
649 | int | ||
650 | main (int argc, char *const *argv) | ||
651 | { | ||
652 | int flags; | ||
653 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
654 | {'n', "nick", "NAME", | ||
655 | gettext_noop ("set the nickname to use (required)"), | ||
656 | 1, &GNUNET_GETOPT_set_string, &nickname}, | ||
657 | {'r', "room", "NAME", | ||
658 | gettext_noop ("set the chat room to join"), | ||
659 | 1, &GNUNET_GETOPT_set_string, &room_name}, | ||
660 | GNUNET_GETOPT_OPTION_END | ||
661 | }; | ||
662 | |||
663 | flags = fcntl (0, F_GETFL, 0); | ||
664 | flags |= O_NONBLOCK; | ||
665 | fcntl (0, F_SETFL, flags); | ||
666 | return (GNUNET_OK == | ||
667 | GNUNET_PROGRAM_run (argc, | ||
668 | argv, | ||
669 | "gnunet-chat", | ||
670 | gettext_noop ("Join a chat on GNUnet."), | ||
671 | options, &run, NULL)) ? ret : 1; | ||
672 | } | ||
673 | |||
674 | /* end of gnunet-chat.c */ | ||