2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
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 Affero General Public License for more details.
17 * CLI tool to interact with the social service.
19 * @author Gabor X Toth
25 #include "gnunet_util_lib.h"
26 #include "gnunet_social_service.h"
28 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
30 #define DATA2ARG(data) data, sizeof (data)
32 /* operations corresponding to API calls */
38 static int op_host_enter;
40 /** --host-reconnect */
41 static int op_host_reconnect;
44 static int op_host_leave;
46 /** --host-announce */
47 static int op_host_announce;
50 static int op_host_assign;
53 static int op_guest_enter;
55 /** --guest-reconnect */
56 static int op_guest_reconnect;
59 static int op_guest_leave;
62 static int op_guest_talk;
67 /** --replay-latest */
68 static int op_replay_latest;
71 static int op_look_at;
74 static int op_look_for;
80 static char *opt_app = "cli";
83 static char *opt_place;
92 static char *opt_peer;
95 static int opt_follow;
98 static int opt_welcome;
104 static char *opt_method;
107 // FIXME: should come from STDIN
108 static char *opt_data;
111 static char *opt_name;
114 static unsigned long long opt_start;
117 static unsigned long long opt_until;
120 static unsigned long long opt_limit;
128 /** are we waiting for service to close our connection */
129 static char is_disconnecting = 0;
131 /** Task handle for timeout termination. */
132 struct GNUNET_SCHEDULER_Task *timeout_task;
134 const struct GNUNET_CONFIGURATION_Handle *cfg;
136 struct GNUNET_PeerIdentity peer, this_peer;
138 struct GNUNET_SOCIAL_App *app;
140 /** public key of connected place */
141 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
143 struct GNUNET_PSYC_Slicer *slicer;
145 struct GNUNET_SOCIAL_Ego *ego;
146 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
148 struct GNUNET_SOCIAL_Host *hst;
149 struct GNUNET_SOCIAL_Guest *gst;
150 struct GNUNET_SOCIAL_Place *plc;
152 const char *method_received;
159 * Callback called after the host or guest place disconnected.
162 disconnected (void *cls)
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n");
165 GNUNET_SCHEDULER_shutdown ();
170 * Callback called after the application disconnected.
173 app_disconnected (void *cls)
175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n");
180 GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL);
184 GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL);
189 GNUNET_SCHEDULER_shutdown ();
195 * Disconnect from connected GNUnet services.
200 // handle that we get called several times from several places, but should we?
201 if (!is_disconnecting++) {
202 GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL);
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting);
209 scheduler_shutdown (void *cls)
216 * Callback called when the program failed to finish the requested operation in time.
221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n");
226 schedule_success (void *cls)
234 schedule_fail (void *cls)
241 * Schedule exit with success result.
246 if (timeout_task != NULL)
248 GNUNET_SCHEDULER_cancel (timeout_task);
251 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL);
256 * Schedule exit with failure result.
261 if (timeout_task != NULL)
263 GNUNET_SCHEDULER_cancel (timeout_task);
266 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL);
274 * Callback notifying about the host has left and stopped hosting the place.
276 * This also indicates the end of the connection to the service.
279 host_left (void *cls)
281 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
282 "The host has left the place.\n");
288 * Leave a place permanently and stop hosting a place.
293 GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL);
300 * Callback notifying about the guest has left the place.
302 * This also indicates the end of the connection to the service.
305 guest_left (void *cls)
307 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
308 "Guest has left the place.\n");
313 * Leave a place permanently as guest.
318 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
319 // FIXME: wrong use of vars
320 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
321 "_message", DATA2ARG ("Leaving."));
322 GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL);
323 GNUNET_PSYC_env_destroy (env);
329 /* ANNOUNCE / ASSIGN / TALK */
332 struct TransmitClosure
340 * Callback notifying about available buffer space to write message data
341 * when transmitting messages using host_announce() or guest_talk()
344 notify_data (void *cls, uint16_t *data_size, void *data)
346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347 "Transmit notify data: %u bytes available\n",
350 struct TransmitClosure *tmit = cls;
351 uint16_t size = tmit->size < *data_size ? tmit->size : *data_size;
353 GNUNET_memcpy (data, tmit->data, size);
360 if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow)
374 * Host announcement - send a message to the place.
377 host_announce (const char *method, const char *data, size_t data_size)
379 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
380 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
381 "_foo", DATA2ARG ("bar baz"));
383 tmit = (struct TransmitClosure) {};
385 tmit.size = data_size;
387 GNUNET_SOCIAL_host_announce (hst, method, env,
389 GNUNET_SOCIAL_ANNOUNCE_NONE);
390 GNUNET_PSYC_env_destroy (env);
395 * Assign a state var of @a name to the value of @a data.
398 host_assign (const char *name, const char *data, size_t data_size)
400 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
401 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
402 name, data, data_size);
404 tmit = (struct TransmitClosure) {};
405 GNUNET_SOCIAL_host_announce (hst, "_assign", env,
407 GNUNET_SOCIAL_ANNOUNCE_NONE);
408 GNUNET_PSYC_env_destroy (env);
413 * Guest talk request to host.
416 guest_talk (const char *method,
417 const char *data, size_t data_size)
419 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
420 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
421 "_foo", DATA2ARG ("bar baz"));
423 tmit = (struct TransmitClosure) {};
425 tmit.size = data_size;
427 GNUNET_SOCIAL_guest_talk (gst, method, env,
429 GNUNET_SOCIAL_TALK_NONE);
430 GNUNET_PSYC_env_destroy (env);
438 * Callback notifying about the end of history replay results.
441 recv_history_replay_result (void *cls, int64_t result,
442 const void *data, uint16_t data_size)
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Received history replay result: %" PRId64 "\n"
447 result, data_size, (const char *) data);
449 if (op_replay || op_replay_latest)
457 * Replay history between a given @a start and @a end message IDs,
458 * optionally filtered by a method @a prefix.
461 history_replay (uint64_t start, uint64_t end, const char *prefix)
463 GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix,
464 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
466 recv_history_replay_result,
472 * Replay latest @a limit messages.
475 history_replay_latest (uint64_t limit, const char *prefix)
477 GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix,
478 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
480 recv_history_replay_result,
489 * Callback notifying about the end of state var results.
492 look_result (void *cls, int64_t result_code,
493 const void *data, uint16_t data_size)
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496 "Received look result: %" PRId64 "\n", result_code);
498 if (op_look_at || op_look_for)
506 * Callback notifying about a state var result.
510 const struct GNUNET_MessageHeader *mod,
514 uint32_t full_value_size)
516 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
517 "Received var: %s\n%.*s\n",
518 name, value_size, (const char *) value);
523 * Look for a state var using exact match of the name.
526 look_at (const char *full_name)
528 GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL);
533 * Look for state vars by name prefix.
536 look_for (const char *name_prefix)
538 GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL);
546 * Callback notifying about the start of a new incoming message.
549 slicer_recv_method (void *cls,
550 const struct GNUNET_PSYC_MessageHeader *msg,
551 const struct GNUNET_PSYC_MessageMethod *meth,
553 const char *method_name)
555 method_received = method_name;
556 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
557 "Received method for message ID %" PRIu64 ":\n"
559 message_id, method_name, ntohl (meth->flags));
560 /* routing header is missing, so we just print double newline */
562 /* we output . instead of | to indicate that this is not proper PSYC syntax */
563 /* FIXME: use libpsyc here */
568 * Callback notifying about an incoming modifier.
571 slicer_recv_modifier (void *cls,
572 const struct GNUNET_PSYC_MessageHeader *msg,
573 const struct GNUNET_MessageHeader *pmsg,
575 enum GNUNET_PSYC_Operator oper,
579 uint16_t full_value_size)
582 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
583 "Received modifier for message ID %" PRIu64 ":\n"
584 "%c%s: %.*s (size: %u)\n",
585 message_id, oper, name, value_size, (const char *) value, value_size);
587 /* obviously not binary safe */
588 printf("%c%s\t%.*s\n",
589 oper, name, value_size, (const char *) value);
595 * Callback notifying about an incoming data fragment.
598 slicer_recv_data (void *cls,
599 const struct GNUNET_PSYC_MessageHeader *msg,
600 const struct GNUNET_MessageHeader *pmsg,
606 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
607 "Received data for message ID %" PRIu64 ":\n"
609 message_id, data_size, (const char *) data);
611 /* obviously not binary safe */
613 method_received, data_size, (const char *) data);
619 * Callback notifying about the end of a message.
622 slicer_recv_eom (void *cls,
623 const struct GNUNET_PSYC_MessageHeader *msg,
624 const struct GNUNET_MessageHeader *pmsg,
626 uint8_t is_cancelled)
629 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
630 "Received end of message ID %" PRIu64
632 message_id, is_cancelled);
637 * Create a slicer for receiving message parts.
639 static struct GNUNET_PSYC_Slicer *
642 slicer = GNUNET_PSYC_slicer_create ();
644 /* register slicer to receive incoming messages with any method name */
645 GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
646 slicer_recv_method, slicer_recv_modifier,
647 slicer_recv_data, slicer_recv_eom, NULL);
656 * Callback called when the guest receives an entry decision from the host.
658 * It is called once after using guest_enter() or guest_enter_by_name(),
659 * in case of a reconnection only the local enter callback is called.
662 guest_recv_entry_decision (void *cls,
664 const struct GNUNET_PSYC_Message *entry_msg)
666 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
667 "Guest received entry decision %d\n",
670 if (NULL != entry_msg)
672 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
673 const char *method_name = NULL;
674 const void *data = NULL;
675 uint16_t data_size = 0;
676 struct GNUNET_PSYC_MessageHeader *
677 pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
678 GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
681 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
683 method_name, data_size, (const char *) data);
686 if (op_guest_enter && !opt_follow)
694 * Callback called after a guest connection is established to the local service.
697 guest_recv_local_enter (void *cls, int result,
698 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
699 uint64_t max_message_id)
701 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
702 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
703 "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
704 pub_str, max_message_id);
705 GNUNET_free (pub_str);
706 GNUNET_assert (0 <= result);
708 if (op_guest_enter && !opt_follow)
716 * Create entry request message.
718 static struct GNUNET_PSYC_Message *
719 guest_enter_msg_create ()
721 const char *method_name = "_request_enter";
722 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
723 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
724 "_foo", DATA2ARG ("bar"));
725 void *data = "let me in";
726 uint16_t data_size = strlen (data) + 1;
728 return GNUNET_PSYC_message_create (method_name, env, data, data_size);
733 * Enter a place as guest, using its public key and peer ID.
736 guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
737 const struct GNUNET_PeerIdentity *peer)
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740 "Entering to place as guest.\n");
744 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
749 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
750 gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key,
751 GNUNET_PSYC_SLAVE_JOIN_NONE,
752 peer, 0, NULL, join_msg, slicer_create (),
753 guest_recv_local_enter,
754 guest_recv_entry_decision, NULL);
755 GNUNET_free (join_msg);
756 plc = GNUNET_SOCIAL_guest_get_place (gst);
761 * Enter a place as guest using its GNS address.
764 guest_enter_by_name (const char *gns_name)
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
767 "Entering to place by name as guest.\n");
769 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
770 gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
772 guest_recv_local_enter,
773 guest_recv_entry_decision, NULL);
774 GNUNET_free (join_msg);
775 plc = GNUNET_SOCIAL_guest_get_place (gst);
783 * Callback called when a @a nym wants to enter the place.
785 * The request needs to be replied with an entry decision.
788 host_answer_door (void *cls,
789 struct GNUNET_SOCIAL_Nym *nym,
790 const char *method_name,
791 struct GNUNET_PSYC_Environment *env,
795 const struct GNUNET_CRYPTO_EcdsaPublicKey *
796 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
798 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
800 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
801 "Entry request: %s\n", nym_str);
802 GNUNET_free (nym_str);
806 struct GNUNET_PSYC_Message *
807 resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
808 DATA2ARG ("Welcome, nym!"));
809 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp);
814 struct GNUNET_PSYC_Message *
815 resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL,
816 DATA2ARG ("Go away!"));
817 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp);
826 * Callback called when a @a nym has left the place.
829 host_farewell (void *cls,
830 const struct GNUNET_SOCIAL_Nym *nym,
831 struct GNUNET_PSYC_Environment *env)
833 const struct GNUNET_CRYPTO_EcdsaPublicKey *
834 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
836 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
838 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
839 "Farewell: %s\n", nym_str);
840 GNUNET_free (nym_str);
845 * Callback called after the host entered the place.
848 host_entered (void *cls, int result,
849 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
850 uint64_t max_message_id)
852 place_pub_key = *pub_key;
853 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
854 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
855 "Host entered: %s, max_message_id: %" PRIu64 "\n",
856 pub_str, max_message_id);
857 GNUNET_free (pub_str);
859 if (op_host_enter && !opt_follow)
867 * Enter and start hosting a place.
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
876 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
881 hst = GNUNET_SOCIAL_host_enter (app, ego,
882 GNUNET_PSYC_CHANNEL_PRIVATE,
883 slicer_create (), host_entered,
884 host_answer_door, host_farewell, NULL);
885 plc = GNUNET_SOCIAL_host_get_place (hst);
889 /* PLACE RECONNECT */
893 * Perform operations common to both host & guest places.
898 static int first_run = GNUNET_YES;
899 if (GNUNET_NO == first_run)
901 first_run = GNUNET_NO;
904 history_replay (opt_start, opt_until, opt_method);
906 else if (op_replay_latest) {
907 history_replay_latest (opt_limit, opt_method);
909 else if (op_look_at) {
912 else if (op_look_for) {
919 * Callback called after reconnecting to a host place.
922 host_reconnected (void *cls, int result,
923 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
924 uint64_t max_message_id)
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927 "Host reconnected.\n");
932 else if (op_host_announce) {
933 host_announce (opt_method, opt_data, strlen (opt_data));
935 else if (op_host_assign) {
936 host_assign (opt_name, opt_data, strlen (opt_data) + 1);
939 place_reconnected ();
945 * Callback called after reconnecting to a guest place.
948 guest_reconnected (void *cls, int result,
949 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
950 uint64_t max_message_id)
952 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "Guest reconnected to place %s.\n", place_pub_str);
955 GNUNET_free (place_pub_str);
957 if (op_guest_leave) {
960 else if (op_guest_talk) {
961 guest_talk (opt_method, opt_data, strlen (opt_data));
964 place_reconnected ();
973 * Callback called after the ego and place callbacks.
976 app_connected (void *cls)
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "App connected: %p\n", cls);
985 else if (op_host_enter)
989 else if (op_guest_enter)
993 guest_enter_by_name (opt_gns);
999 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer,
1003 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1013 guest_enter (&place_pub_key, &peer);
1021 * Callback notifying about a host place available for reconnection.
1024 app_recv_host (void *cls,
1025 struct GNUNET_SOCIAL_HostConnection *hconn,
1026 struct GNUNET_SOCIAL_Ego *ego,
1027 const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
1028 enum GNUNET_SOCIAL_AppPlaceState place_state)
1030 char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
1031 printf ("Host\t%s\n", host_pub_str);
1032 GNUNET_free (host_pub_str);
1034 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1035 || op_replay || op_replay_latest
1036 || op_look_at || op_look_for)
1037 && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
1039 hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
1040 host_answer_door, host_farewell, NULL);
1041 plc = GNUNET_SOCIAL_host_get_place (hst);
1047 * Callback notifying about a guest place available for reconnection.
1050 app_recv_guest (void *cls,
1051 struct GNUNET_SOCIAL_GuestConnection *gconn,
1052 struct GNUNET_SOCIAL_Ego *ego,
1053 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
1054 enum GNUNET_SOCIAL_AppPlaceState place_state)
1056 char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
1057 printf ("Guest\t%s\n", guest_pub_str);
1058 GNUNET_free (guest_pub_str);
1060 if ((op_guest_reconnect || op_guest_leave || op_guest_talk
1061 || op_replay || op_replay_latest
1062 || op_look_at || op_look_for)
1063 && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
1065 gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
1066 slicer_create (), guest_reconnected, NULL);
1067 plc = GNUNET_SOCIAL_guest_get_place (gst);
1073 * Callback notifying about an available ego.
1076 app_recv_ego (void *cls,
1077 struct GNUNET_SOCIAL_Ego *e,
1078 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
1081 char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
1082 printf ("Ego\t%s\t%s\n", s, name);
1085 if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
1086 || (NULL != opt_ego && 0 == strcmp (opt_ego, name)))
1096 * Establish application connection to receive available egos and places.
1099 app_connect (void *cls)
1101 app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
1111 * Main function run by the scheduler.
1113 * @param cls closure
1114 * @param args remaining command-line arguments
1115 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1116 * @param c configuration
1119 run (void *cls, char *const *args, const char *cfgfile,
1120 const struct GNUNET_CONFIGURATION_Handle *c)
1123 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
1126 opt_method = "message";
1133 || op_host_enter || op_host_reconnect || op_host_leave
1134 || op_host_announce || op_host_assign
1135 || op_guest_enter || op_guest_reconnect
1136 || op_guest_leave || op_guest_talk
1137 || op_replay || op_replay_latest
1138 || op_look_at || op_look_for))
1141 fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
1144 GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
1147 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL);
1150 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1151 || op_guest_reconnect || (op_guest_enter && !opt_gns)
1152 || op_guest_leave || op_guest_talk
1153 || op_replay || op_replay_latest
1154 || op_look_at || op_look_for)
1156 || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
1160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1161 _("--place missing or invalid.\n"));
1162 /* FIXME: why does it segfault here? */
1170 GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
1175 _("Public key `%s' malformed\n"),
1182 GNUNET_SCHEDULER_add_now (app_connect, NULL);
1187 * The main function to obtain peer information.
1189 * @param argc number of arguments from the command line
1190 * @param argv command line arguments
1191 * @return 0 ok, 1 on error
1194 main (int argc, char *const *argv)
1197 struct GNUNET_GETOPT_CommandLineOption options[] = {
1199 * gnunet program options in addition to the ones below:
1201 * -c, --config=FILENAME
1202 * -l, --logfile=LOGFILE
1203 * -L, --log=LOGLEVEL
1210 GNUNET_GETOPT_option_flag ('A',
1212 gettext_noop ("assign --name in state to --data"),
1215 GNUNET_GETOPT_option_flag ('B',
1217 gettext_noop ("say good-bye and leave somebody else's place"),
1220 GNUNET_GETOPT_option_flag ('C',
1222 gettext_noop ("create a place"),
1225 GNUNET_GETOPT_option_flag ('D',
1227 gettext_noop ("destroy a place we were hosting"),
1230 GNUNET_GETOPT_option_flag ('E',
1232 gettext_noop ("enter somebody else's place"),
1236 GNUNET_GETOPT_option_flag ('F',
1238 gettext_noop ("find state matching name prefix"),
1241 GNUNET_GETOPT_option_flag ('H',
1243 gettext_noop ("replay history of messages up to the given --limit"),
1246 GNUNET_GETOPT_option_flag ('N',
1248 gettext_noop ("reconnect to a previously created place"),
1249 &op_host_reconnect),
1251 GNUNET_GETOPT_option_flag ('P',
1253 gettext_noop ("publish something to a place we are hosting"),
1256 GNUNET_GETOPT_option_flag ('R',
1258 gettext_noop ("reconnect to a previously entered place"),
1259 &op_guest_reconnect),
1261 GNUNET_GETOPT_option_flag ('S',
1263 gettext_noop ("search for state matching exact name"),
1266 GNUNET_GETOPT_option_flag ('T',
1268 gettext_noop ("submit something to somebody's place"),
1271 GNUNET_GETOPT_option_flag ('U',
1273 gettext_noop ("list of egos and subscribed places"),
1276 GNUNET_GETOPT_option_flag ('X',
1278 gettext_noop ("extract and replay history between message IDs --start and --until"),
1284 GNUNET_GETOPT_option_string ('a',
1287 gettext_noop ("application ID to use when connecting"),
1290 GNUNET_GETOPT_option_string ('d',
1293 gettext_noop ("message body or state value"),
1296 GNUNET_GETOPT_option_string ('e',
1299 gettext_noop ("name or public key of ego"),
1302 GNUNET_GETOPT_option_flag ('f',
1304 gettext_noop ("wait for incoming messages"),
1307 GNUNET_GETOPT_option_string ('g',
1310 gettext_noop ("GNS name"),
1313 GNUNET_GETOPT_option_string ('i',
1316 gettext_noop ("peer ID for --guest-enter"),
1319 GNUNET_GETOPT_option_string ('k',
1322 gettext_noop ("name (key) to query from state"),
1325 GNUNET_GETOPT_option_string ('m',
1328 gettext_noop ("method name"),
1331 GNUNET_GETOPT_option_ulong ('n',
1334 gettext_noop ("number of messages to replay from history"),
1337 GNUNET_GETOPT_option_string ('p',
1340 gettext_noop ("key address of place"),
1343 GNUNET_GETOPT_option_ulong ('s',
1346 gettext_noop ("start message ID for history replay"),
1349 GNUNET_GETOPT_option_flag ('w',
1351 gettext_noop ("respond to entry requests by admitting all guests"),
1354 GNUNET_GETOPT_option_ulong ('u',
1357 gettext_noop ("end message ID for history replay"),
1360 GNUNET_GETOPT_option_flag ('y',
1362 gettext_noop ("respond to entry requests by refusing all guests"),
1365 GNUNET_GETOPT_OPTION_END
1368 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1372 _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n");
1374 "gnunet-social [--status]\n"
1376 "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n"
1377 "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n"
1378 "gnunet-social --host-leave --place <PUBKEY>\n"
1379 "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1380 // FIXME: some state ops not implemented yet (no hurry)
1381 // "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1382 // "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1383 // "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1384 "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1386 "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n"
1387 "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n"
1388 "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n"
1389 "gnunet-social --guest-leave --place <PUBKEY>\n"
1390 "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1392 "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
1393 "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
1395 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
1396 "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
1398 res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL);
1400 GNUNET_free ((void *) argv);
1402 if (GNUNET_OK == res)