-fixing last FTBFS issues
[oweals/gnunet.git] / src / conversation / gnunet-conversation.c
1 /*
2                  This file is part of GNUnet.
3                  (C)
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, InGNUNET_SERVERc., 59 Temple Place - Suite 330,
18                  Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file conversation/gnunet-conversation.c
23  * @brief conversation implementation
24  * @author Simon Dieterle
25  * @author Andreas Fuchs
26  */
27 #include <gnunet/platform.h>
28 #include <gnunet/gnunet_constants.h>
29 #include <gnunet/gnunet_util_lib.h>
30 #include "gnunet_conversation_service.h"
31 #include <fcntl.h>
32
33 #define MAX_MESSAGE_LENGTH   (32 * 1024)
34
35 /**
36 * CONVERSATION handle
37 */
38 struct GNUNET_CONVERSATION_Handle *conversation = NULL;
39
40 /**
41 * Task which handles the commands
42 */
43 static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task;
44
45 /**
46 * Function declareation for executing a action
47 */
48 typedef int (*ActionFunction) (const char *argumetns, const void *xtra);
49
50 /**
51 * Structure which defines a command
52 */
53 struct VoipCommand
54 {
55   const char *command;
56   ActionFunction Action;
57   const char *helptext;
58 };
59
60 /******************************************************************************/
61 /***********************         DECLARATIONS         *************************/
62 /******************************************************************************/
63
64 static int do_help (const char *args, const void *xtra);
65
66 /******************************************************************************/
67 /***********************         Functions            *************************/
68 /******************************************************************************/
69
70
71 /**
72  * Method called whenever a call is incoming
73  *
74  * @param cls closure
75  * @param handle to the conversation session
76  * @param caller peer that calls you
77  */
78 void
79 call_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle,
80               const struct GNUNET_PeerIdentity *caller)
81 {
82   FPRINTF (stdout, _("Incoming call from peer: %s\n"),
83            GNUNET_i2s_full (caller));
84 }
85
86 /**
87  * Method called whenever a call is rejected
88  *
89  * @param cls closure
90  * @param handle to the conversation session
91  * @param peer peer that rejected your call
92  */
93 void
94 reject_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle, int reason,
95                 const struct GNUNET_PeerIdentity *peer)
96 {
97   FPRINTF (stdout, _("Peer %s rejected your call. Reason: %d\n"),
98            GNUNET_i2s_full (peer), reason);
99 }
100
101 /**
102  * Method called whenever a notification is there
103  *
104  * @param cls closure
105  * @param handle to the conversation session
106  * @param type the type of the notification
107  * @param peer peer that the notification is about
108  */
109 void
110 notification_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle, int type,
111                       const struct GNUNET_PeerIdentity *peer)
112 {
113   switch (type)
114     {
115     case NotificationType_SERVICE_BLOCKED:
116       FPRINTF (stdout, _("The service is already in use. Try again later."));
117
118       break;
119
120     case NotificationType_NO_PEER:
121       FPRINTF (stdout, _("The Peer you were calling is no correct peer.\n"));
122
123       break;
124
125     case NotificationType_NO_ANSWER:
126       FPRINTF (stdout, _("Peer %s did not answer your call.\n"),
127                GNUNET_i2s_full (peer));
128
129       break;
130
131     case NotificationType_AVAILABLE_AGAIN:
132       FPRINTF (stdout, _("Peer %s is now available.\n"),
133                GNUNET_i2s_full (peer));
134
135       break;
136
137     case NotificationType_CALL_ACCEPTED:
138       FPRINTF (stdout, _("Peer %s has accepted your call.\n"),
139                GNUNET_i2s_full (peer));
140
141       break;
142
143     case NotificationType_CALL_TERMINATED:
144       FPRINTF (stdout, _("Peer %s has terminated the call.\n"),
145                GNUNET_i2s_full (peer));
146       break;
147     }
148
149 }
150
151 /**
152  * Method called whenever a notification for missed calls is there
153  *
154  * @param cls closure
155  * @param handle to the conversation session
156  * @param missed_calls a list of missed calls
157  */
158 void
159 missed_call_handler (void *cls, struct GNUNET_CONVERSATION_Handle *handle,
160                      struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls)
161 {
162   FPRINTF (stdout, _("You have missed calls.\n"));
163 }
164
165 /**
166 * Terminating the client
167 */
168 static int
169 do_quit (const char *args, const void *xtra)
170 {
171   return GNUNET_SYSERR;
172 }
173
174 /**
175 *
176 */
177 static int
178 do_unknown (const char *msg, const void *xtra)
179 {
180   FPRINTF (stderr, _("Unknown command `%s'\n"), msg);
181   return GNUNET_OK;
182 }
183
184 /**
185 * Initiating a new call
186 */
187 static int
188 do_call (const char *arg, const void *xtra)
189 {
190   char *callee = GNUNET_strdup (arg);
191   FPRINTF (stdout, _("Initiating call to: %s\n"), callee);
192   GNUNET_CONVERSATION_call (conversation, callee, GNUNET_YES);
193
194   return GNUNET_OK;
195 }
196
197 /**
198 * Initiating a new call
199 */
200 static int
201 do_call_peer (const char *arg, const void *xtra)
202 {
203   char *callee = GNUNET_strdup (arg);
204   FPRINTF (stdout, _("Initiating call to: %s\n"), callee);
205   GNUNET_CONVERSATION_call (conversation, callee, GNUNET_NO);
206
207   return GNUNET_OK;
208 }
209
210 /**
211 * Accepting an incoming call
212 */
213 static int
214 do_accept (const char *args, const void *xtra)
215 {
216   FPRINTF (stdout, _("Accepting the call\n"));
217   GNUNET_CONVERSATION_accept (conversation);
218
219   return GNUNET_OK;
220 }
221
222 /**
223 * Rejecting a call
224 */
225 static int
226 do_reject (const char *args, const void *xtra)
227 {
228   FPRINTF (stdout, _("Rejecting the call\n"));
229   GNUNET_CONVERSATION_reject (conversation);
230
231   return GNUNET_OK;
232 }
233
234 /**
235 * Terminating a call
236 */
237 static int
238 do_hang_up (const char *args, const void *xtra)
239 {
240   FPRINTF (stdout, _("Terminating the call\n"));
241   GNUNET_CONVERSATION_hangup (conversation);
242
243   return GNUNET_OK;
244 }
245
246 /**
247  * List of supported commands.
248  */
249 static struct VoipCommand commands[] = {
250   {"/call ", &do_call, gettext_noop ("Use `/call gads_record'")},
251   {"/callpeer ", &do_call_peer,
252    gettext_noop ("Use `/call private_key' to call a person")},
253   {"/accept", &do_accept,
254    gettext_noop ("Use `/accept' to accept an incoming call")},
255   {"/terminate", &do_hang_up,
256    gettext_noop ("Use `/terminate' to end a call")},
257   {"/reject", &do_reject,
258    gettext_noop ("Use `/rejet' to reject an incoming call")},
259   {"/quit", &do_quit, gettext_noop ("Use `/quit' to terminate gnunet-conversation")},
260   {"/help", &do_help,
261    gettext_noop ("Use `/help command' to get help for a specific command")},
262   {"/", &do_unknown, NULL},
263   {"", &do_unknown, NULL},
264   {NULL, NULL, NULL},
265 };
266
267 /**
268 *
269 */
270 static int
271 do_help (const char *args, const void *xtra)
272 {
273   int i;
274
275   i = 0;
276   while ((NULL != args) && (0 != strlen (args)) &&
277          (commands[i].Action != &do_help))
278     {
279       if (0 ==
280           strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1))
281         {
282           FPRINTF (stdout, "%s\n", gettext (commands[i].helptext));
283           return GNUNET_OK;
284         }
285       i++;
286     }
287   i = 0;
288   FPRINTF (stdout, "%s", "Available commands:");
289   while (commands[i].Action != &do_help)
290     {
291       FPRINTF (stdout, " %s", gettext (commands[i].command));
292       i++;
293     }
294   FPRINTF (stdout, "%s", "\n");
295   FPRINTF (stdout, "%s\n", gettext (commands[i].helptext));
296   return GNUNET_OK;
297 }
298
299 /**
300 *
301 */
302 static void
303 do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
304 {
305   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown task\n");
306   GNUNET_CONVERSATION_disconnect (conversation);
307
308   if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK)
309     {
310       GNUNET_SCHEDULER_cancel (handle_cmd_task);
311       handle_cmd_task = GNUNET_SCHEDULER_NO_TASK;
312     }
313
314   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown task finished\n");
315 }
316
317 /**
318 *
319 */
320 void
321 handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
322 {
323   char message[MAX_MESSAGE_LENGTH + 1];
324   int i;
325
326   /* read message from command line and handle it */
327   memset (message, 0, MAX_MESSAGE_LENGTH + 1);
328   if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin))
329     goto next;
330   if (strlen (message) == 0)
331     goto next;
332   if (message[strlen (message) - 1] == '\n')
333     message[strlen (message) - 1] = '\0';
334   if (strlen (message) == 0)
335     goto next;
336   i = 0;
337   while ((NULL != commands[i].command) &&
338          (0 !=
339           strncasecmp (commands[i].command, message,
340                        strlen (commands[i].command))))
341     i++;
342   if (GNUNET_OK !=
343       commands[i].Action (&message[strlen (commands[i].command)], NULL))
344     goto out;
345
346 next:
347   handle_cmd_task =
348     GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply
349                                                 (GNUNET_TIME_UNIT_MILLISECONDS,
350                                                  100),
351                                                 GNUNET_SCHEDULER_PRIORITY_UI,
352                                                 &handle_command, NULL);
353   return;
354
355 out:
356   handle_cmd_task = GNUNET_SCHEDULER_NO_TASK;
357   GNUNET_SCHEDULER_shutdown ();
358 }
359
360 /**
361  * Main function that will be run by the scheduler.
362  *
363  * @param cls closure
364  * @param args remaining command-line arguments
365  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
366  * @param c configuration
367  */
368 static void
369 run (void *cls, char *const *args, const char *cfgfile,
370      const struct GNUNET_CONFIGURATION_Handle *c)
371 {
372   if (NULL ==
373       (conversation =
374        GNUNET_CONVERSATION_connect (c, NULL, &call_handler, &reject_handler,
375                             &notification_handler, &missed_call_handler)))
376     {
377       FPRINTF (stderr, "%s", _("Could not access CONVERSATION service.  Exiting.\n"));
378       return;
379     }
380
381   handle_cmd_task =
382     GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
383                                         &handle_command, NULL);
384   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task,
385                                 NULL);
386 }
387
388 /** * The main function to conversation.
389  *
390  * @param argc number of arguments from the command line
391  * @param argv command line arguments
392  * @return 0 ok, 1 on error
393  */
394 int
395 main (int argc, char *const *argv)
396 {
397   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
398     GNUNET_GETOPT_OPTION_END
399   };
400
401   int flags;
402   int ret;
403
404   flags = fcntl (0, F_GETFL, 0);
405   flags |= O_NONBLOCK;
406   fcntl (0, F_SETFL, flags);
407
408   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
409     return 2;
410
411   ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-conversation",
412                             gettext_noop ("Print information about conversation."),
413                             options, &run, NULL);
414   GNUNET_free ((void *) argv);
415
416   return ret;
417 }
418
419 /* end of gnunet-conversation.c */