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
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * CLI tool to interact with the social service.
24 * @author Gabor X Toth
30 #include "gnunet_util_lib.h"
31 #include "gnunet_social_service.h"
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
35 #define DATA2ARG(data) data, sizeof (data)
37 /* operations corresponding to API calls */
43 static int op_host_enter;
45 /** --host-reconnect */
46 static int op_host_reconnect;
49 static int op_host_leave;
51 /** --host-announce */
52 static int op_host_announce;
55 static int op_host_assign;
58 static int op_guest_enter;
60 /** --guest-reconnect */
61 static int op_guest_reconnect;
64 static int op_guest_leave;
67 static int op_guest_talk;
70 static char *op_replay;
72 /** --replay-latest */
73 static char *op_replay_latest;
76 static int op_look_at;
79 static int op_look_for;
85 static char *opt_app = "cli";
88 static char *opt_place;
97 static char *opt_peer;
100 static int opt_follow;
103 static int opt_welcome;
109 static char *opt_method;
112 // FIXME: should come from STDIN
113 static char *opt_data;
116 static char *opt_name;
119 static uint64_t opt_start;
122 static uint64_t opt_until;
125 static int opt_limit;
133 /** are we waiting for service to close our connection */
134 static char is_disconnecting = 0;
136 /** Task handle for timeout termination. */
137 struct GNUNET_SCHEDULER_Task *timeout_task;
139 const struct GNUNET_CONFIGURATION_Handle *cfg;
141 struct GNUNET_PeerIdentity peer, this_peer;
143 struct GNUNET_SOCIAL_App *app;
145 /** public key of connected place */
146 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
148 struct GNUNET_PSYC_Slicer *slicer;
150 struct GNUNET_SOCIAL_Ego *ego;
151 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
153 struct GNUNET_SOCIAL_Host *hst;
154 struct GNUNET_SOCIAL_Guest *gst;
155 struct GNUNET_SOCIAL_Place *plc;
157 const char *method_received;
164 * Callback called after the host or guest place disconnected.
167 disconnected (void *cls)
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n");
170 GNUNET_SCHEDULER_shutdown ();
175 * Callback called after the application disconnected.
178 app_disconnected (void *cls)
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n");
185 GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL);
189 GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL);
194 GNUNET_SCHEDULER_shutdown ();
200 * Disconnect from connected GNUnet services.
205 // handle that we get called several times from several places, but should we?
206 if (!is_disconnecting++) {
207 GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL);
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting);
214 scheduler_shutdown (void *cls)
221 * Callback called when the program failed to finish the requested operation in time.
226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n");
231 schedule_success (void *cls)
239 schedule_fail (void *cls)
246 * Schedule exit with success result.
251 if (timeout_task != NULL)
253 GNUNET_SCHEDULER_cancel (timeout_task);
256 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL);
261 * Schedule exit with failure result.
266 if (timeout_task != NULL)
268 GNUNET_SCHEDULER_cancel (timeout_task);
271 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL);
279 * Callback notifying about the host has left and stopped hosting the place.
281 * This also indicates the end of the connection to the service.
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 "The host has left the place.\n");
293 * Leave a place permanently and stop hosting a place.
298 GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL);
305 * Callback notifying about the guest has left the place.
307 * This also indicates the end of the connection to the service.
310 guest_left (void *cls)
312 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
313 "Guest has left the place.\n");
318 * Leave a place permanently as guest.
323 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
324 // FIXME: wrong use of vars
325 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
326 "_message", DATA2ARG ("Leaving."));
327 GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL);
328 GNUNET_PSYC_env_destroy (env);
334 /* ANNOUNCE / ASSIGN / TALK */
337 struct TransmitClosure
345 * Callback notifying about available buffer space to write message data
346 * when transmitting messages using host_announce() or guest_talk()
349 notify_data (void *cls, uint16_t *data_size, void *data)
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Transmit notify data: %u bytes available\n",
355 struct TransmitClosure *tmit = cls;
356 uint16_t size = tmit->size < *data_size ? tmit->size : *data_size;
358 GNUNET_memcpy (data, tmit->data, size);
365 if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow)
379 * Host announcement - send a message to the place.
382 host_announce (const char *method, const char *data, size_t data_size)
384 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
385 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
386 "_foo", DATA2ARG ("bar baz"));
388 tmit = (struct TransmitClosure) {};
390 tmit.size = data_size;
392 GNUNET_SOCIAL_host_announce (hst, method, env,
394 GNUNET_SOCIAL_ANNOUNCE_NONE);
395 GNUNET_PSYC_env_destroy (env);
400 * Assign a state var of @a name to the value of @a data.
403 host_assign (const char *name, const char *data, size_t data_size)
405 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
406 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
407 name, data, data_size);
409 tmit = (struct TransmitClosure) {};
410 GNUNET_SOCIAL_host_announce (hst, "_assign", env,
412 GNUNET_SOCIAL_ANNOUNCE_NONE);
413 GNUNET_PSYC_env_destroy (env);
418 * Guest talk request to host.
421 guest_talk (const char *method,
422 const char *data, size_t data_size)
424 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
425 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
426 "_foo", DATA2ARG ("bar baz"));
428 tmit = (struct TransmitClosure) {};
430 tmit.size = data_size;
432 GNUNET_SOCIAL_guest_talk (gst, method, env,
434 GNUNET_SOCIAL_TALK_NONE);
435 GNUNET_PSYC_env_destroy (env);
443 * Callback notifying about the end of history replay results.
446 recv_history_replay_result (void *cls, int64_t result,
447 const void *data, uint16_t data_size)
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Received history replay result: %" PRId64 "\n"
452 result, data_size, (const char *) data);
454 if (op_replay || op_replay_latest)
462 * Replay history between a given @a start and @a end message IDs,
463 * optionally filtered by a method @a prefix.
466 history_replay (uint64_t start, uint64_t end, const char *prefix)
468 GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix,
469 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
471 recv_history_replay_result,
477 * Replay latest @a limit messages.
480 history_replay_latest (uint64_t limit, const char *prefix)
482 GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix,
483 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
485 recv_history_replay_result,
494 * Callback notifying about the end of state var results.
497 look_result (void *cls, int64_t result_code,
498 const void *data, uint16_t data_size)
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501 "Received look result: %" PRId64 "\n", result_code);
503 if (op_look_at || op_look_for)
511 * Callback notifying about a state var result.
515 const struct GNUNET_MessageHeader *mod,
519 uint32_t full_value_size)
521 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
522 "Received var: %s\n%.*s\n",
523 name, value_size, (const char *) value);
528 * Look for a state var using exact match of the name.
531 look_at (const char *full_name)
533 GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL);
538 * Look for state vars by name prefix.
541 look_for (const char *name_prefix)
543 GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL);
551 * Callback notifying about the start of a new incoming message.
554 slicer_recv_method (void *cls,
555 const struct GNUNET_PSYC_MessageHeader *msg,
556 const struct GNUNET_PSYC_MessageMethod *meth,
558 const char *method_name)
560 method_received = method_name;
561 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
562 "Received method for message ID %" PRIu64 ":\n"
564 message_id, method_name, ntohl (meth->flags));
565 /* routing header is missing, so we just print double newline */
567 /* we output . instead of | to indicate that this is not proper PSYC syntax */
568 /* FIXME: use libpsyc here */
573 * Callback notifying about an incoming modifier.
576 slicer_recv_modifier (void *cls,
577 const struct GNUNET_PSYC_MessageHeader *msg,
578 const struct GNUNET_MessageHeader *pmsg,
580 enum GNUNET_PSYC_Operator oper,
584 uint16_t full_value_size)
587 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
588 "Received modifier for message ID %" PRIu64 ":\n"
589 "%c%s: %.*s (size: %u)\n",
590 message_id, oper, name, value_size, (const char *) value, value_size);
592 /* obviously not binary safe */
593 printf("%c%s\t%.*s\n",
594 oper, name, value_size, (const char *) value);
600 * Callback notifying about an incoming data fragment.
603 slicer_recv_data (void *cls,
604 const struct GNUNET_PSYC_MessageHeader *msg,
605 const struct GNUNET_MessageHeader *pmsg,
611 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
612 "Received data for message ID %" PRIu64 ":\n"
614 message_id, data_size, (const char *) data);
616 /* obviously not binary safe */
618 method_received, data_size, (const char *) data);
624 * Callback notifying about the end of a message.
627 slicer_recv_eom (void *cls,
628 const struct GNUNET_PSYC_MessageHeader *msg,
629 const struct GNUNET_MessageHeader *pmsg,
631 uint8_t is_cancelled)
634 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
635 "Received end of message ID %" PRIu64
637 message_id, is_cancelled);
642 * Create a slicer for receiving message parts.
644 static struct GNUNET_PSYC_Slicer *
647 slicer = GNUNET_PSYC_slicer_create ();
649 /* register slicer to receive incoming messages with any method name */
650 GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
651 slicer_recv_method, slicer_recv_modifier,
652 slicer_recv_data, slicer_recv_eom, NULL);
661 * Callback called when the guest receives an entry decision from the host.
663 * It is called once after using guest_enter() or guest_enter_by_name(),
664 * in case of a reconnection only the local enter callback is called.
667 guest_recv_entry_decision (void *cls,
669 const struct GNUNET_PSYC_Message *entry_msg)
671 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
672 "Guest received entry decision %d\n",
675 if (NULL != entry_msg)
677 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
678 const char *method_name = NULL;
679 const void *data = NULL;
680 uint16_t data_size = 0;
681 struct GNUNET_PSYC_MessageHeader *
682 pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
683 GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
686 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
688 method_name, data_size, (const char *) data);
691 if (op_guest_enter && !opt_follow)
699 * Callback called after a guest connection is established to the local service.
702 guest_recv_local_enter (void *cls, int result,
703 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
704 uint64_t max_message_id)
706 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
707 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
708 "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
709 pub_str, max_message_id);
710 GNUNET_free (pub_str);
711 GNUNET_assert (0 <= result);
713 if (op_guest_enter && !opt_follow)
721 * Create entry requset message.
723 static struct GNUNET_PSYC_Message *
724 guest_enter_msg_create ()
726 const char *method_name = "_request_enter";
727 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
728 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
729 "_foo", DATA2ARG ("bar"));
730 void *data = "let me in";
731 uint16_t data_size = strlen (data) + 1;
733 return GNUNET_PSYC_message_create (method_name, env, data, data_size);
738 * Enter a place as guest, using its public key and peer ID.
741 guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
742 const struct GNUNET_PeerIdentity *peer)
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745 "Entering to place as guest.\n");
749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
754 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
755 gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key,
756 GNUNET_PSYC_SLAVE_JOIN_NONE,
757 peer, 0, NULL, join_msg, slicer_create (),
758 guest_recv_local_enter,
759 guest_recv_entry_decision, NULL);
760 GNUNET_free (join_msg);
761 plc = GNUNET_SOCIAL_guest_get_place (gst);
766 * Enter a place as guest using its GNS address.
769 guest_enter_by_name (const char *gns_name)
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Entering to place by name as guest.\n");
774 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
775 gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
777 guest_recv_local_enter,
778 guest_recv_entry_decision, NULL);
779 GNUNET_free (join_msg);
780 plc = GNUNET_SOCIAL_guest_get_place (gst);
788 * Callback called when a @a nym wants to enter the place.
790 * The request needs to be replied with an entry decision.
793 host_answer_door (void *cls,
794 struct GNUNET_SOCIAL_Nym *nym,
795 const char *method_name,
796 struct GNUNET_PSYC_Environment *env,
800 const struct GNUNET_CRYPTO_EcdsaPublicKey *
801 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
803 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
805 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
806 "Entry request: %s\n", nym_str);
807 GNUNET_free (nym_str);
811 struct GNUNET_PSYC_Message *
812 resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
813 DATA2ARG ("Welcome, nym!"));
814 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp);
819 struct GNUNET_PSYC_Message *
820 resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL,
821 DATA2ARG ("Go away!"));
822 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp);
831 * Callback called when a @a nym has left the place.
834 host_farewell (void *cls,
835 const struct GNUNET_SOCIAL_Nym *nym,
836 struct GNUNET_PSYC_Environment *env)
838 const struct GNUNET_CRYPTO_EcdsaPublicKey *
839 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
841 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
843 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
844 "Farewell: %s\n", nym_str);
845 GNUNET_free (nym_str);
850 * Callback called after the host entered the place.
853 host_entered (void *cls, int result,
854 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
855 uint64_t max_message_id)
857 place_pub_key = *pub_key;
858 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
860 "Host entered: %s, max_message_id: %" PRIu64 "\n",
861 pub_str, max_message_id);
862 GNUNET_free (pub_str);
864 if (op_host_enter && !opt_follow)
872 * Enter and start hosting a place.
877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
886 hst = GNUNET_SOCIAL_host_enter (app, ego,
887 GNUNET_PSYC_CHANNEL_PRIVATE,
888 slicer_create (), host_entered,
889 host_answer_door, host_farewell, NULL);
890 plc = GNUNET_SOCIAL_host_get_place (hst);
894 /* PLACE RECONNECT */
898 * Perform operations common to both host & guest places.
903 static int first_run = GNUNET_YES;
904 if (GNUNET_NO == first_run)
906 first_run = GNUNET_NO;
909 history_replay (opt_start, opt_until, opt_method);
911 else if (op_replay_latest) {
912 history_replay_latest (opt_limit, opt_method);
914 else if (op_look_at) {
917 else if (op_look_for) {
924 * Callback called after reconnecting to a host place.
927 host_reconnected (void *cls, int result,
928 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
929 uint64_t max_message_id)
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "Host reconnected.\n");
937 else if (op_host_announce) {
938 host_announce (opt_method, opt_data, strlen (opt_data));
940 else if (op_host_assign) {
941 host_assign (opt_name, opt_data, strlen (opt_data) + 1);
944 place_reconnected ();
950 * Callback called after reconnecting to a guest place.
953 guest_reconnected (void *cls, int result,
954 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
955 uint64_t max_message_id)
957 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959 "Guest reconnected to place %s.\n", place_pub_str);
960 GNUNET_free (place_pub_str);
962 if (op_guest_leave) {
965 else if (op_guest_talk) {
966 guest_talk (opt_method, opt_data, strlen (opt_data));
969 place_reconnected ();
978 * Callback called after the ego and place callbacks.
981 app_connected (void *cls)
983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
984 "App connected: %p\n", cls);
990 else if (op_host_enter)
994 else if (op_guest_enter)
998 guest_enter_by_name (opt_gns);
1004 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer,
1008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1018 guest_enter (&place_pub_key, &peer);
1026 * Callback notifying about a host place available for reconnection.
1029 app_recv_host (void *cls,
1030 struct GNUNET_SOCIAL_HostConnection *hconn,
1031 struct GNUNET_SOCIAL_Ego *ego,
1032 const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
1033 enum GNUNET_SOCIAL_AppPlaceState place_state)
1035 char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
1036 printf ("Host\t%s\n", host_pub_str);
1037 GNUNET_free (host_pub_str);
1039 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1040 || op_replay || op_replay_latest
1041 || op_look_at || op_look_for)
1042 && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
1044 hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
1045 host_answer_door, host_farewell, NULL);
1046 plc = GNUNET_SOCIAL_host_get_place (hst);
1052 * Callback notifying about a guest place available for reconnection.
1055 app_recv_guest (void *cls,
1056 struct GNUNET_SOCIAL_GuestConnection *gconn,
1057 struct GNUNET_SOCIAL_Ego *ego,
1058 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
1059 enum GNUNET_SOCIAL_AppPlaceState place_state)
1061 char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
1062 printf ("Guest\t%s\n", guest_pub_str);
1063 GNUNET_free (guest_pub_str);
1065 if ((op_guest_reconnect || op_guest_leave || op_guest_talk
1066 || op_replay || op_replay_latest
1067 || op_look_at || op_look_for)
1068 && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
1070 gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
1071 slicer_create (), guest_reconnected, NULL);
1072 plc = GNUNET_SOCIAL_guest_get_place (gst);
1078 * Callback notifying about an available ego.
1081 app_recv_ego (void *cls,
1082 struct GNUNET_SOCIAL_Ego *e,
1083 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
1086 char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
1087 printf ("Ego\t%s\t%s\n", s, name);
1090 if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
1091 || (NULL != opt_ego && 0 == strcmp (opt_ego, name)))
1101 * Establish application connection to receive available egos and places.
1104 app_connect (void *cls)
1106 app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
1116 * Main function run by the scheduler.
1118 * @param cls closure
1119 * @param args remaining command-line arguments
1120 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1121 * @param c configuration
1124 run (void *cls, char *const *args, const char *cfgfile,
1125 const struct GNUNET_CONFIGURATION_Handle *c)
1128 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
1131 opt_method = "message";
1138 || op_host_enter || op_host_reconnect || op_host_leave
1139 || op_host_announce || op_host_assign
1140 || op_guest_enter || op_guest_reconnect
1141 || op_guest_leave || op_guest_talk
1142 || op_replay || op_replay_latest
1143 || op_look_at || op_look_for))
1146 fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
1149 GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
1152 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL);
1155 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1156 || op_guest_reconnect || (op_guest_enter && !opt_gns)
1157 || op_guest_leave || op_guest_talk
1158 || op_replay || op_replay_latest
1159 || op_look_at || op_look_for)
1161 || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _("--place missing or invalid.\n"));
1167 /* FIXME: why does it segfault here? */
1175 GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
1180 _("Public key `%s' malformed\n"),
1187 GNUNET_SCHEDULER_add_now (app_connect, NULL);
1192 * The main function to obtain peer information.
1194 * @param argc number of arguments from the command line
1195 * @param argv command line arguments
1196 * @return 0 ok, 1 on error
1199 main (int argc, char *const *argv)
1202 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1204 * gnunet program options in addition to the ones below:
1206 * -c, --config=FILENAME
1207 * -l, --logfile=LOGFILE
1208 * -L, --log=LOGLEVEL
1215 { 'A', "host-assign", NULL,
1216 gettext_noop ("assign --name in state to --data"),
1217 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_assign },
1219 { 'B', "guest-leave", NULL,
1220 gettext_noop ("say good-bye and leave somebody else's place"),
1221 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_leave },
1223 { 'C', "host-enter", NULL,
1224 gettext_noop ("create a place"),
1225 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_enter },
1227 { 'D', "host-leave", NULL,
1228 gettext_noop ("destroy a place we were hosting"),
1229 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_leave },
1231 { 'E', "guest-enter", NULL,
1232 gettext_noop ("enter somebody else's place"),
1233 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_enter },
1235 { 'F', "look-for", NULL,
1236 gettext_noop ("find state matching name prefix"),
1237 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_for },
1239 { 'H', "replay-latest", NULL,
1240 gettext_noop ("replay history of messages up to the given --limit"),
1241 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay_latest },
1243 { 'N', "host-reconnect", NULL,
1244 gettext_noop ("reconnect to a previously created place"),
1245 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_reconnect },
1247 { 'P', "host-announce", NULL,
1248 gettext_noop ("publish something to a place we are hosting"),
1249 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_announce },
1251 { 'R', "guest-reconnect", NULL,
1252 gettext_noop ("reconnect to a previously entered place"),
1253 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_reconnect },
1255 { 'S', "look-at", NULL,
1256 gettext_noop ("search for state matching exact name"),
1257 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_at },
1259 { 'T', "guest-talk", NULL,
1260 gettext_noop ("submit something to somebody's place"),
1261 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_talk },
1263 { 'U', "status", NULL,
1264 gettext_noop ("list of egos and subscribed places"),
1265 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_status },
1267 { 'X', "replay", NULL,
1268 gettext_noop ("extract and replay history between message IDs --start and --until"),
1269 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay },
1274 { 'a', "app", "APPLICATION_ID",
1275 gettext_noop ("application ID to use when connecting"),
1276 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_app },
1278 { 'd', "data", "DATA",
1279 gettext_noop ("message body or state value"),
1280 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_data },
1282 { 'e', "ego", "NAME|PUBKEY",
1283 gettext_noop ("name or public key of ego"),
1284 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_ego },
1286 { 'f', "follow", NULL,
1287 gettext_noop ("wait for incoming messages"),
1288 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_follow },
1290 { 'g', "gns", "GNS_NAME",
1291 gettext_noop ("GNS name"),
1292 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_gns },
1294 { 'i', "peer", "PEER_ID",
1295 gettext_noop ("peer ID for --guest-enter"),
1296 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_peer },
1298 { 'k', "name", "VAR_NAME",
1299 gettext_noop ("name (key) to query from state"),
1300 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_name },
1302 { 'm', "method", "METHOD_NAME",
1303 gettext_noop ("method name"),
1304 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_method },
1306 { 'n', "limit", NULL,
1307 gettext_noop ("number of messages to replay from history"),
1308 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_limit },
1310 { 'p', "place", "PUBKEY",
1311 gettext_noop ("key address of place"),
1312 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_place },
1314 { 's', "start", NULL,
1315 gettext_noop ("start message ID for history replay"),
1316 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_start },
1318 { 'w', "welcome", NULL,
1319 gettext_noop ("respond to entry requests by admitting all guests"),
1320 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_welcome },
1322 { 'u', "until", NULL,
1323 gettext_noop ("end message ID for history replay"),
1324 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_until },
1326 { 'y', "deny", NULL,
1327 gettext_noop ("respond to entry requests by refusing all guests"),
1328 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_deny },
1330 GNUNET_GETOPT_OPTION_END
1333 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1337 _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n");
1339 "gnunet-social [--status]\n"
1341 "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n"
1342 "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n"
1343 "gnunet-social --host-leave --place <PUBKEY>\n"
1344 "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1345 // FIXME: some state ops not implemented yet (no hurry)
1346 // "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1347 // "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1348 // "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1349 "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1351 "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n"
1352 "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n"
1353 "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n"
1354 "gnunet-social --guest-leave --place <PUBKEY>\n"
1355 "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1357 "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
1358 "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
1360 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
1361 "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
1363 res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL);
1365 GNUNET_free ((void *) argv);
1367 if (GNUNET_OK == res)