social cli
[oweals/gnunet.git] / src / social / gnunet-social.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2016 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * CLI tool to interact with the social service.
23  *
24  * @author Gabor X Toth
25  */
26
27 #include <inttypes.h>
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_social_service.h"
32
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34
35 /* operations corresponding to API calls */
36
37 /** --host-enter */
38 static int op_host_enter;
39
40 /** --host-leave */
41 static int op_host_leave;
42
43 /** --host-announce */
44 static int op_host_announce;
45
46 /** --guest-enter */
47 static int op_guest_enter;
48
49 /** --guest-leave */
50 static int op_guest_leave;
51
52 /** --guest-talk */
53 static int op_guest_talk;
54
55 /** --history-replay */
56 static char *op_history_replay;
57
58 /** --history-replay-latest */
59 static char *op_history_replay_latest;
60
61 /** --look-at */
62 static int op_look_at;
63
64 /** --look-for */
65 static int op_look_for;
66
67
68 /* options */
69
70 /** --app */
71 static char *opt_app = "cli";
72
73 /** --place */
74 static char *opt_place;
75
76 /** --ego */
77 static char *opt_ego;
78
79 /** --follow */
80 static int opt_follow;
81
82 /** --method */
83 static char *opt_method;
84
85 /** --data */
86 // FIXME: could also come from STDIN
87 static char *opt_data;
88
89 /** --name */
90 static char *opt_name;
91
92 /** --start */
93 static uint64_t opt_start;
94
95 /** --end */
96 static uint64_t opt_end;
97
98 /** --limit */
99 static int opt_limit;
100
101
102 /* global vars */
103
104 /** exit code */
105 static int ret = 1;
106
107 /** Task handle for timeout termination. */
108 struct GNUNET_SCHEDULER_Task *timeout_task;
109
110 const struct GNUNET_CONFIGURATION_Handle *cfg;
111
112 struct GNUNET_CORE_Handle *core;
113 struct GNUNET_PeerIdentity peer;
114
115 struct GNUNET_SOCIAL_App *app;
116
117 /** public key of connected place */
118 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
119
120 /** hash of @a place_pub_key */
121 struct GNUNET_HashCode place_pub_hash;
122
123 struct GNUNET_PSYC_Slicer *slicer;
124
125 struct GNUNET_SOCIAL_Ego *ego;
126 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
127
128 struct GNUNET_SOCIAL_Host *hst;
129 struct GNUNET_SOCIAL_Guest *gst;
130 struct GNUNET_SOCIAL_Place *plc;
131
132
133 static void
134 cleanup ()
135 {
136
137 }
138
139
140 /**
141  * Terminate the test case (failure).
142  *
143  * @param cls NULL
144  */
145 static void
146 timeout (void *cls)
147 {
148   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout\n");
149   cleanup ();
150 }
151
152
153 static void
154 host_leave (struct GNUNET_SOCIAL_Host *host)
155 {
156
157 }
158
159
160 static void
161 host_announce (struct GNUNET_SOCIAL_Host *host,
162                const char *method,
163                const char *data)
164 {
165
166 }
167
168
169 static void
170 guest_leave (struct GNUNET_SOCIAL_Guest *guest)
171 {
172
173 }
174
175
176 static void
177 guest_talk (struct GNUNET_SOCIAL_Guest *guest,
178             const char *method,
179             const char *data)
180 {
181
182 }
183
184
185 static void
186 history_replay (struct GNUNET_SOCIAL_Place *place,
187                 uint64_t start, uint64_t end, const char *prefix)
188 {
189
190 }
191
192
193 static void
194 history_replay_latest (struct GNUNET_SOCIAL_Place *place,
195                        uint64_t limit, const char *prefix)
196 {
197
198 }
199
200
201 static void
202 look_at (struct GNUNET_SOCIAL_Place *place,
203          const char *name)
204 {
205
206 }
207
208
209 static void
210 look_for (struct GNUNET_SOCIAL_Place *place,
211           const char *name)
212 {
213
214 }
215
216 /* SLICER + CALLBACKS */
217
218
219 static void
220 slicer_recv_method (void *cls,
221                     const struct GNUNET_PSYC_MessageHeader *msg,
222                     const struct GNUNET_PSYC_MessageMethod *meth,
223                     uint64_t message_id,
224                     const char *method_name)
225 {
226   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
227               "Received method for message ID %" PRIu64 ":\n"
228               "%s (flags: %x)\n",
229               message_id, method_name, ntohl (meth->flags));
230 }
231
232
233 static void
234 slicer_recv_modifier (void *cls,
235                       const struct GNUNET_PSYC_MessageHeader *msg,
236                       const struct GNUNET_MessageHeader *pmsg,
237                       uint64_t message_id,
238                       enum GNUNET_PSYC_Operator oper,
239                       const char *name,
240                       const void *value,
241                       uint16_t value_size,
242                       uint16_t full_value_size)
243 {
244   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
245               "Received modifier for message ID %" PRIu64 ":\n"
246               "%c%s: %.*s (size: %u)\n",
247               message_id, oper, name, value_size, value, value_size);
248 }
249
250
251 static void
252 slicer_recv_data (void *cls,
253                   const struct GNUNET_PSYC_MessageHeader *msg,
254                   const struct GNUNET_MessageHeader *pmsg,
255                   uint64_t message_id,
256                   const void *data,
257                   uint16_t data_size)
258 {
259   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
260               "Received data for message ID %" PRIu64 ":\n"
261               "%.*s\n",
262               message_id, data_size, data);
263 }
264
265
266 static void
267 slicer_recv_eom (void *cls,
268                 const struct GNUNET_PSYC_MessageHeader *msg,
269                 const struct GNUNET_MessageHeader *pmsg,
270                 uint64_t message_id,
271                 uint8_t is_cancelled)
272 {
273   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
274               "Received end of message ID %" PRIu64
275               ", cancelled: %u\n",
276               message_id, is_cancelled);
277 }
278
279
280 static struct GNUNET_PSYC_Slicer *
281 slicer_create ()
282 {
283   slicer = GNUNET_PSYC_slicer_create ();
284
285   /* register slicer to receive incoming messages with any method name */
286   GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
287                                  slicer_recv_method, slicer_recv_modifier,
288                                  slicer_recv_data, slicer_recv_eom, NULL);
289   return slicer;
290 }
291
292
293 /* GUEST ENTER + CALLBACKS */
294
295
296 static void
297 guest_recv_entry_decision (void *cls,
298                            int is_admitted,
299                            const struct GNUNET_PSYC_Message *entry_msg)
300 {
301   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
302               "Guest received entry decision %d\n",
303               is_admitted);
304
305   if (NULL != entry_msg)
306   {
307     struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
308     const char *method_name = NULL;
309     const void *data = NULL;
310     uint16_t data_size = 0;
311     struct GNUNET_PSYC_MessageHeader *
312       pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
313     GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
314     GNUNET_free (pmsg);
315
316     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317                 "%s\n%.*s\n",
318                 method_name, data_size, data);
319   }
320 }
321
322
323 static void
324 guest_recv_local_enter (void *cls, int result,
325                         const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
326                         uint64_t max_message_id)
327 {
328   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
329               "Guest entered to local place: %d, max_message_id: %" PRIu64 "\n",
330               result, max_message_id);
331   GNUNET_assert (0 <= result);
332 }
333
334
335 static struct GNUNET_PSYC_Message *
336 guest_enter_msg_create ()
337 {
338   const char *method_name = "_request_enter";
339   struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
340   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
341                        "_foo", "bar", sizeof ("bar"));
342   void *data = "let me in";
343   uint16_t data_size = strlen (data) + 1;
344
345   return GNUNET_PSYC_message_create (method_name, env, data, data_size);
346 }
347
348
349 static void
350 guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
351              struct GNUNET_PeerIdentity *peer)
352 {
353   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
354               "Entering to place as guest.\n");
355
356   gst = GNUNET_SOCIAL_guest_enter (app, ego, &place_pub_key,
357                                    GNUNET_PSYC_SLAVE_JOIN_NONE,
358                                    peer, 0, NULL, guest_enter_msg_create (),
359                                    slicer_create (),
360                                    guest_recv_local_enter,
361                                    guest_recv_entry_decision, NULL);
362   plc = GNUNET_SOCIAL_guest_get_place (gst);
363 }
364
365
366 static void
367 guest_enter_by_name (const char *gns_name)
368 {
369   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
370               "Entering to place by name as guest.\n");
371
372   gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
373                                            guest_enter_msg_create (), slicer,
374                                            guest_recv_local_enter,
375                                            guest_recv_entry_decision, NULL);
376   plc = GNUNET_SOCIAL_guest_get_place (gst);
377 }
378
379
380
381 /* HOST ENTER + CALLBACKS */
382
383
384 static void
385 host_answer_door (void *cls,
386                   struct GNUNET_SOCIAL_Nym *nym,
387                   const char *method_name,
388                   struct GNUNET_PSYC_Environment *env,
389                   const void *data,
390                   size_t data_size)
391 {
392   const struct GNUNET_CRYPTO_EcdsaPublicKey *
393     nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
394   char *
395     nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
396
397   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
398               "Entry request: %s\n", nym_str);
399   GNUNET_free (nym_str);
400 }
401
402
403 static void
404 host_farewell (void *cls,
405                const struct GNUNET_SOCIAL_Nym *nym,
406                struct GNUNET_PSYC_Environment *env)
407 {
408   const struct GNUNET_CRYPTO_EcdsaPublicKey *
409     nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
410   char *
411     nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
412
413   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
414               "Farewell: %s\n", nym_str);
415   GNUNET_free (nym_str);
416 }
417
418
419 static void
420 host_entered (void *cls, int result,
421               const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
422               uint64_t max_message_id)
423 {
424   place_pub_key = *pub_key;
425   GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
426   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
427               "Entered: %s, max_message_id: %" PRIu64 "\n",
428               GNUNET_h2s_full (&place_pub_hash), max_message_id);
429 }
430
431
432 static void
433 host_enter ()
434 {
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
436
437   hst = GNUNET_SOCIAL_host_enter (app, ego,
438                                   GNUNET_PSYC_CHANNEL_PRIVATE,
439                                   slicer_create (), host_entered,
440                                   host_answer_door, host_farewell, NULL);
441   plc = GNUNET_SOCIAL_host_get_place (hst);
442 }
443
444
445 /* RECONNECT CALLBACKS */
446
447 static void
448 place_reconnected ()
449 {
450   if (op_history_replay) {
451     history_replay (plc, opt_start, opt_end, opt_method);
452   }
453   else if (op_history_replay_latest) {
454     history_replay_latest (plc, opt_limit, opt_method);
455   }
456   else if (op_look_at) {
457     look_at (plc, opt_name);
458   }
459   else if (op_look_for) {
460     look_for (plc, opt_name);
461   }
462 }
463
464
465 static void
466 host_reconnected (void *cls, int result,
467                   const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
468                   uint64_t max_message_id)
469 {
470   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
471               "Host reconnected\n");
472
473   if (op_host_leave) {
474     host_leave (hst);
475   }
476   else if (op_host_announce) {
477     host_announce (hst, opt_method, opt_data);
478   }
479   else {
480     place_reconnected ();
481   }
482 }
483
484
485 static void
486 guest_reconnected (void *cls, int result,
487                    const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
488                    uint64_t max_message_id)
489 {
490   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
491               "Guest reconnected\n");
492
493   if (op_guest_leave) {
494     guest_leave (gst);
495   }
496   else if (op_guest_talk) {
497     guest_talk (gst, opt_method, opt_data);
498   }
499   else {
500     place_reconnected ();
501   }
502 }
503
504
505 /* APP CALLBACKS */
506
507
508 static void
509 app_connected (void *cls)
510 {
511   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
512               "App connected: %p\n", cls);
513
514   if (op_host_enter) {
515     host_enter ();
516   }
517   else if (op_guest_enter) {
518     guest_enter (&place_pub_key);
519   }
520 }
521
522
523 static void
524 app_recv_host (void *cls,
525                struct GNUNET_SOCIAL_HostConnection *hconn,
526                struct GNUNET_SOCIAL_Ego *ego,
527                const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
528                enum GNUNET_SOCIAL_AppPlaceState place_state)
529 {
530   struct GNUNET_HashCode host_pub_hash;
531   GNUNET_CRYPTO_hash (host_pub_key, sizeof (*host_pub_key), &host_pub_hash);
532   char *
533     host_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (guest_pub_key);
534
535   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
536               "Host: %s (%s)\n",
537               GNUNET_h2s_full (&host_pub_hash), host_pub_str);
538   GNUNET_free (host_pub_str);
539
540   if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
541   {
542     hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
543                                               host_answer_door, host_farewell, NULL);
544     plc = GNUNET_SOCIAL_host_get_place (hst);
545   }
546 }
547
548
549 static void
550 app_recv_guest (void *cls,
551                 struct GNUNET_SOCIAL_GuestConnection *gconn,
552                 struct GNUNET_SOCIAL_Ego *ego,
553                 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
554                 enum GNUNET_SOCIAL_AppPlaceState place_state)
555 {
556   struct GNUNET_HashCode guest_pub_hash;
557   GNUNET_CRYPTO_hash (guest_pub_key, sizeof (*guest_pub_key), &guest_pub_hash);
558   char *
559     guest_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (guest_pub_key);
560
561   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
562               "Guest: %s (%s)\n",
563               GNUNET_h2s_full (&guest_pub_hash), guest_pub_str);
564   GNUNET_free (guest_pub_str);
565
566   if (0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
567   {
568     gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
569                                                slicer_create (), guest_reconnected, NULL);
570     plc = GNUNET_SOCIAL_guest_get_place (gst);
571   }
572 }
573
574
575 static void
576 app_recv_ego (void *cls,
577               struct GNUNET_SOCIAL_Ego *ego,
578               const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
579               const char *name)
580 {
581   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
582               "Ego: %s\t%s\n",
583               name, GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key));
584 }
585
586
587 static void
588 app_connect ()
589 {
590   app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
591                                    app_recv_ego,
592                                    app_recv_host,
593                                    app_recv_guest,
594                                    app_connected,
595                                    NULL);
596 }
597
598 /* CORE CALLBACKS */
599
600
601 static void
602 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
603 {
604   peer = *my_identity;
605   app_connect ();
606 }
607
608
609 /**
610  * Main function run by the scheduler.
611  *
612  * @param cls closure
613  * @param args remaining command-line arguments
614  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
615  * @param cfg configuration
616  */
617 static void
618 run (void *cls, char *const *args, const char *cfgfile,
619      const struct GNUNET_CONFIGURATION_Handle *c)
620 {
621   cfg = c;
622
623   if (!opt_follow)
624   {
625     timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout, NULL);
626   }
627
628   if (op_host_enter && NULL != opt_place)
629   {
630     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
631                 _ ("--place must not be specified when using --host-enter\n"));
632     return;
633   }
634
635   if (!opt_place
636       || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
637                                                                   strlen (opt_place),
638                                                                   &place_pub_key))
639   {
640     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
641                 _ ("--place missing or invalid.\n"));
642     return;
643   }
644
645   if (opt_ego)
646   {
647     GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
648                                                 strlen (opt_ego),
649                                                 &ego_pub_key);
650   }
651
652   if (opt_peer)
653   {
654     // FIXME: peer ID from string
655   }
656
657   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
658                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
659 }
660
661
662 /**
663  * The main function to obtain peer information.
664  *
665  * @param argc number of arguments from the command line
666  * @param argv command line arguments
667  * @return 0 ok, 1 on error
668  */
669 int
670 main (int argc, char *const *argv)
671 {
672   int res;
673   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
674     /* operations */
675
676     { 'E', "host-enter", NULL,
677       _ ("create a place for nyms to join"),
678       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_enter },
679
680     { 'L', "host-leave", NULL,
681       _ ("destroy a place we were hosting"),
682       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_leave },
683
684     { 'A', "host-announce", NULL,
685       _ ("publish something to a place we are hosting"),
686       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_announce },
687
688     { 'e', "guest-enter", NULL,
689       _ ("join somebody else's place"),
690       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_enter },
691
692     { 'l', "guest-leave", NULL,
693       _ ("leave somebody else's place"),
694       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_leave },
695
696     { 't', "guest-talk", NULL,
697       _ ("submit something to somebody's place"),
698       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_talk },
699
700     { 'R', "history-replay", NULL,
701       _ ("replay history of messages between message IDs --start and --end"),
702       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_history_replay },
703
704     { 'r', "history-replay-latest", NULL,
705       _ ("replay history of latest messages up to the given --limit"),
706       GNUNET_NO, &GNUNET_GETOPT_set_one, &op_history_replay_latest },
707
708     /* options */
709
710     { 'A', "app", "application ID",
711       _ ("application ID to use when connecting"),
712       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_app },
713
714     { 'p', "place", "PUBKEY",
715       _ ("public key of place"),
716       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_place },
717
718     { 'g', "ego", "PUBKEY",
719       _ ("public key of ego"),
720       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_place },
721
722     { 'f', "follow", NULL,
723       _ ("wait for incoming messages"),
724       GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_follow },
725
726     { 'm', "method", "METHOD_NAME",
727       _ ("method name"),
728       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_method },
729
730     { 'd', "data", "DATA",
731       _ ("message body to transmit"),
732       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_data },
733
734     { 'n', "name", "VAR_NAME",
735       _ ("state var name to query"),
736       GNUNET_NO, &GNUNET_GETOPT_set_string, &opt_name },
737
738     { 'a', "start", NULL,
739       _ ("start message ID for history replay"),
740       GNUNET_NO, &GNUNET_GETOPT_set_ulong, &opt_start },
741
742     { 'z', "end", NULL,
743       _ ("end message ID for history replay"),
744       GNUNET_NO, &GNUNET_GETOPT_set_ulong, &opt_end },
745
746     { 'n', "limit", NULL,
747       _ ("number of messages to replay from history"),
748       GNUNET_NO, &GNUNET_GETOPT_set_ulong, &opt_limit },
749
750     GNUNET_GETOPT_OPTION_END
751   };
752
753   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
754     return 2;
755
756   const char *help =
757     _ ("interact with the social service: enter/leave, send/receive messages, access history and state")m;
758   const char *usage =
759     "gnunet-social --host-enter --ego <name or pubkey> [--listen]\n"
760     "gnunet-social --host-leave --place <pubkey>\n"
761     "gnunet-social --host-announce --place <pubkey> --method <method_name> --data <message body>\n"
762     "\n"
763     "gnunet-social --guest-enter --place <pubkey> --ego <name or pubkey> [--listen]\n"
764     "gnunet-social --guest-leave --place <pubkey>\n"
765     "gnunet-social --guest-talk --place <pubkey> --method <method_nmae> --data <data>\n"
766     "\n"
767     "gnunet-social --history-replay --place <pubkey> --start <msgid> --end <msgid>  [--method <method_prefix>]\n"
768     "gnunet-social --history-replay-latest --place <pubkey> --limit <msg_limit> [--method <method_prefix>]\n"
769     "\n"
770     "gnunet-social --look-at --place <pubkey> --name <full_name>\n"
771     "gnunet-social --look-for --place <pubkey> --name <name_prefix>\n";
772
773   res = GNUNET_PROGRAM_run (argc, argv, usage,
774                             help, options, &run, NULL);
775
776   GNUNET_free ((void *) argv);
777
778   if (GNUNET_OK == res)
779     return ret;
780   else
781     return 1;
782 }