tools: Fix compilation in MeeGo
[framework/connectivity/connman.git] / tools / wispr.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <termios.h>
34
35 #include <gweb/gweb.h>
36
37 #define DEFAULT_URL  "http://www.connman.net/online/status.html"
38
39 static GTimer *timer;
40
41 static GMainLoop *main_loop;
42
43 static void web_debug(const char *str, void *data)
44 {
45         g_print("%s: %s\n", (const char *) data, str);
46 }
47
48 static void sig_term(int sig)
49 {
50         g_main_loop_quit(main_loop);
51 }
52
53 static const char *message_type_to_string(int message_type)
54 {
55         switch (message_type) {
56         case 100:
57                 return "Initial redirect message";
58         case 110:
59                 return "Proxy notification";
60         case 120:
61                 return "Authentication notification";
62         case 130:
63                 return "Logoff notification";
64         case 140:
65                 return "Response to Authentication Poll";
66         case 150:
67                 return "Response to Abort Login";
68         }
69
70         return NULL;
71 }
72
73 static const char *response_code_to_string(int response_code)
74 {
75         switch (response_code) {
76         case 0:
77                 return "No error";
78         case 50:
79                 return "Login succeeded";
80         case 100:
81                 return "Login failed";
82         case 102:
83                 return "RADIUS server error/timeout";
84         case 105:
85                 return "RADIUS server not enabled";
86         case 150:
87                 return "Logoff succeeded";
88         case 151:
89                 return "Login aborted";
90         case 200:
91                 return "Proxy detection/repeat operation";
92         case 201:
93                 return "Authentication pending";
94         case 255:
95                 return "Access gateway internal error";
96         }
97
98         return NULL;
99 }
100
101 struct wispr_msg {
102         gboolean has_error;
103         const char *current_element;
104         int message_type;
105         int response_code;
106         char *login_url;
107         char *abort_login_url;
108         char *logoff_url;
109         char *access_procedure;
110         char *access_location;
111         char *location_name;
112 };
113
114 static inline void wispr_msg_init(struct wispr_msg *msg)
115 {
116         msg->has_error = FALSE;
117         msg->current_element = NULL;
118
119         msg->message_type = -1;
120         msg->response_code = -1;
121
122         g_free(msg->login_url);
123         msg->login_url = NULL;
124
125         g_free(msg->abort_login_url);
126         msg->abort_login_url = NULL;
127
128         g_free(msg->logoff_url);
129         msg->logoff_url = NULL;
130
131         g_free(msg->access_procedure);
132         msg->access_procedure = NULL;
133
134         g_free(msg->access_location);
135         msg->access_location = NULL;
136
137         g_free(msg->location_name);
138         msg->location_name = NULL;
139 }
140
141 struct wispr_session {
142         GWeb *web;
143         GWebParser *parser;
144         guint request;
145         struct wispr_msg msg;
146         char *username;
147         char *password;
148         char *originurl;
149         char *formdata;
150 };
151
152 static gboolean execute_login(gpointer user_data);
153
154 static struct {
155         const char *str;
156         enum {
157                 WISPR_ELEMENT_NONE,
158                 WISPR_ELEMENT_ACCESS_PROCEDURE,
159                 WISPR_ELEMENT_ACCESS_LOCATION,
160                 WISPR_ELEMENT_LOCATION_NAME,
161                 WISPR_ELEMENT_LOGIN_URL,
162                 WISPR_ELEMENT_ABORT_LOGIN_URL,
163                 WISPR_ELEMENT_MESSAGE_TYPE,
164                 WISPR_ELEMENT_RESPONSE_CODE,
165                 WISPR_ELEMENT_NEXT_URL,
166                 WISPR_ELEMENT_DELAY,
167                 WISPR_ELEMENT_REPLY_MESSAGE,
168                 WISPR_ELEMENT_LOGIN_RESULTS_URL,
169                 WISPR_ELEMENT_LOGOFF_URL,
170         } element;
171 } wispr_element_map[] = {
172         { "AccessProcedure",    WISPR_ELEMENT_ACCESS_PROCEDURE  },
173         { "AccessLocation",     WISPR_ELEMENT_ACCESS_LOCATION   },
174         { "LocationName",       WISPR_ELEMENT_LOCATION_NAME     },
175         { "LoginURL",           WISPR_ELEMENT_LOGIN_URL         },
176         { "AbortLoginURL",      WISPR_ELEMENT_ABORT_LOGIN_URL   },
177         { "MessageType",        WISPR_ELEMENT_MESSAGE_TYPE      },
178         { "ResponseCode",       WISPR_ELEMENT_RESPONSE_CODE     },
179         { "NextURL",            WISPR_ELEMENT_NEXT_URL          },
180         { "Delay",              WISPR_ELEMENT_DELAY             },
181         { "ReplyMessage",       WISPR_ELEMENT_REPLY_MESSAGE     },
182         { "LoginResultsURL",    WISPR_ELEMENT_LOGIN_RESULTS_URL },
183         { "LogoffURL",          WISPR_ELEMENT_LOGOFF_URL        },
184         { NULL,                 WISPR_ELEMENT_NONE              },
185 };
186
187 static void start_element_handler(GMarkupParseContext *context,
188                                         const gchar *element_name,
189                                         const gchar **attribute_names,
190                                         const gchar **attribute_values,
191                                         gpointer user_data, GError **error)
192 {
193         struct wispr_msg *msg = user_data;
194
195         msg->current_element = element_name;
196 }
197
198 static void end_element_handler(GMarkupParseContext *context,
199                                         const gchar *element_name,
200                                         gpointer user_data, GError **error)
201 {
202         struct wispr_msg *msg = user_data;
203
204         msg->current_element = NULL;
205 }
206
207 static void text_handler(GMarkupParseContext *context,
208                                         const gchar *text, gsize text_len,
209                                         gpointer user_data, GError **error)
210 {
211         struct wispr_msg *msg = user_data;
212         int i;
213
214         if (msg->current_element == NULL)
215                 return;
216
217         for (i = 0; wispr_element_map[i].str; i++) {
218                 if (g_str_equal(wispr_element_map[i].str,
219                                         msg->current_element) == FALSE)
220                         continue;
221
222                 switch (wispr_element_map[i].element) {
223                 case WISPR_ELEMENT_NONE:
224                 case WISPR_ELEMENT_ACCESS_PROCEDURE:
225                         g_free(msg->access_procedure);
226                         msg->access_procedure = g_strdup(text);
227                         break;
228                 case WISPR_ELEMENT_ACCESS_LOCATION:
229                         g_free(msg->access_location);
230                         msg->access_location = g_strdup(text);
231                         break;
232                 case WISPR_ELEMENT_LOCATION_NAME:
233                         g_free(msg->location_name);
234                         msg->location_name = g_strdup(text);
235                         break;
236                 case WISPR_ELEMENT_LOGIN_URL:
237                         g_free(msg->login_url);
238                         msg->login_url = g_strdup(text);
239                         break;
240                 case WISPR_ELEMENT_ABORT_LOGIN_URL:
241                         g_free(msg->abort_login_url);
242                         msg->abort_login_url = g_strdup(text);
243                         break;
244                 case WISPR_ELEMENT_MESSAGE_TYPE:
245                         msg->message_type = atoi(text);
246                         break;
247                 case WISPR_ELEMENT_RESPONSE_CODE:
248                         msg->response_code = atoi(text);
249                         break;
250                 case WISPR_ELEMENT_NEXT_URL:
251                 case WISPR_ELEMENT_DELAY:
252                 case WISPR_ELEMENT_REPLY_MESSAGE:
253                 case WISPR_ELEMENT_LOGIN_RESULTS_URL:
254                         break;
255                 case WISPR_ELEMENT_LOGOFF_URL:
256                         g_free(msg->logoff_url);
257                         msg->logoff_url = g_strdup(text);
258                         break;
259                 }
260         }
261 }
262
263 static void error_handler(GMarkupParseContext *context,
264                                         GError *error, gpointer user_data)
265 {
266         struct wispr_msg *msg = user_data;
267
268         msg->has_error = TRUE;
269 }
270
271 static const GMarkupParser wispr_parser = {
272         start_element_handler,
273         end_element_handler,
274         text_handler,
275         NULL,
276         error_handler,
277 };
278
279 static void parser_callback(const char *str, gpointer user_data)
280 {
281         struct wispr_session *wispr = user_data;
282         GMarkupParseContext *context;
283         gboolean result;
284
285         //printf("%s\n", str);
286
287         context = g_markup_parse_context_new(&wispr_parser,
288                         G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
289
290         result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
291         if (result == TRUE)
292                 result = g_markup_parse_context_end_parse(context, NULL);
293
294         g_markup_parse_context_free(context);
295 }
296
297 typedef void (*user_input_cb)(const char *value, gpointer user_data);
298
299 struct user_input_data {
300         GString *str;
301         user_input_cb cb;
302         gpointer user_data;
303         gboolean hidden;
304         int fd;
305         struct termios saved_termios;
306 };
307
308 static void user_callback(struct user_input_data *data)
309 {
310         char *value;
311
312         if (data->hidden == TRUE) {
313                 ssize_t len;
314
315                 len = write(data->fd, "\n", 1);
316                 if (len < 0)
317                         return;
318         }
319
320         tcsetattr(data->fd, TCSADRAIN, &data->saved_termios);
321
322         close(data->fd);
323
324         value = g_string_free(data->str, FALSE);
325
326         if (data->cb)
327                 data->cb(value, data->user_data);
328
329         g_free(value);
330
331         g_free(data);
332 }
333
334 static gboolean keyboard_input(GIOChannel *channel, GIOCondition condition,
335                                                         gpointer user_data)
336 {
337         struct user_input_data *data = user_data;
338         char buf[1];
339         int len;
340
341         len = read(data->fd, buf, 1);
342
343         if (len != 1)
344                 return TRUE;
345
346         if (buf[0] == '\n') {
347                 user_callback(data);
348                 return FALSE;
349         }
350
351         g_string_append_c(data->str, buf[0]);
352
353         if (data->hidden == TRUE)
354                 len = write(data->fd, "*", 1);
355
356         return TRUE;
357 }
358
359 static gboolean user_input(const char *label, gboolean hidden,
360                                 user_input_cb func, gpointer user_data)
361 {
362         struct user_input_data *data;
363         struct termios new_termios;
364         GIOChannel *channel;
365         guint watch;
366         ssize_t len;
367
368         data = g_try_new0(struct user_input_data, 1);
369         if (data == NULL)
370                 return FALSE;
371
372         data->str = g_string_sized_new(32);
373         data->cb = func;
374         data->user_data = user_data;
375         data->hidden = hidden;
376
377         data->fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
378         if (data->fd < 0)
379                 goto error;
380
381         if (tcgetattr(data->fd, &data->saved_termios) < 0) {
382                 close(data->fd);
383                 goto error;
384         }
385
386         new_termios = data->saved_termios;
387         if (data->hidden == TRUE)
388                 new_termios.c_lflag &= ~(ICANON|ECHO);
389         else
390                 new_termios.c_lflag &= ~ICANON;
391         new_termios.c_cc[VMIN] = 1;
392         new_termios.c_cc[VTIME] = 0;
393
394         tcsetattr(data->fd, TCSADRAIN, &new_termios);
395
396         channel = g_io_channel_unix_new(data->fd);
397         g_io_channel_set_encoding(channel, NULL, NULL);
398         g_io_channel_set_buffered(channel, FALSE);
399         watch = g_io_add_watch(channel, G_IO_IN, keyboard_input, data);
400         g_io_channel_unref(channel);
401
402         if (watch == 0)
403                 goto error;
404
405         len = write(data->fd, label, strlen(label));
406         if (len < 0)
407                 goto error;
408
409         len = write(data->fd, ": ", 2);
410         if (len < 0)
411                 goto error;
412
413         return TRUE;
414
415 error:
416         g_string_free(data->str, TRUE);
417         g_free(data);
418
419         return FALSE;
420 }
421
422 static void password_callback(const char *value, gpointer user_data)
423 {
424         struct wispr_session *wispr = user_data;
425
426         g_free(wispr->password);
427         wispr->password = g_strdup(value);
428
429         printf("\n");
430
431         execute_login(wispr);
432 }
433
434 static void username_callback(const char *value, gpointer user_data)
435 {
436         struct wispr_session *wispr = user_data;
437
438         g_free(wispr->username);
439         wispr->username = g_strdup(value);
440
441         if (wispr->password == NULL) {
442                 user_input("Password", TRUE, password_callback, wispr);
443                 return;
444         }
445
446         printf("\n");
447
448         execute_login(wispr);
449 }
450
451 static gboolean wispr_input(const guint8 **data, gsize *length,
452                                                 gpointer user_data)
453 {
454         struct wispr_session *wispr = user_data;
455         GString *buf;
456         gsize count;
457
458         buf = g_string_sized_new(100);
459
460         g_string_append(buf, "button=Login&UserName=");
461         g_string_append_uri_escaped(buf, wispr->username, NULL, FALSE);
462         g_string_append(buf, "&Password=");
463         g_string_append_uri_escaped(buf, wispr->password, NULL, FALSE);
464         g_string_append(buf, "&FNAME=0&OriginatingServer=");
465         g_string_append_uri_escaped(buf, wispr->originurl, NULL, FALSE);
466
467         count = buf->len;
468
469         g_free(wispr->formdata);
470         wispr->formdata = g_string_free(buf, FALSE);
471
472         *data = (guint8 *) wispr->formdata;
473         *length = count;
474
475         return FALSE;
476 }
477
478 static gboolean wispr_result(GWebResult *result, gpointer user_data)
479 {
480         struct wispr_session *wispr = user_data;
481         const guint8 *chunk;
482         gsize length;
483         guint16 status;
484         gdouble elapsed;
485
486         g_web_result_get_chunk(result, &chunk, &length);
487
488         if (length > 0) {
489                 //printf("%s\n", (char *) chunk);
490                 g_web_parser_feed_data(wispr->parser, chunk, length);
491                 return TRUE;
492         }
493
494         g_web_parser_end_data(wispr->parser);
495
496         status = g_web_result_get_status(result);
497
498         g_print("status: %03u\n", status);
499
500         elapsed = g_timer_elapsed(timer, NULL);
501
502         g_print("elapse: %f seconds\n", elapsed);
503
504         if (wispr->msg.message_type < 0) {
505                 const char *redirect;
506
507                 if (status != 302)
508                         goto done;
509
510                 if (g_web_result_get_header(result, "Location",
511                                                         &redirect) == FALSE)
512                         goto done;
513
514                 printf("Redirect URL: %s\n", redirect);
515                 printf("\n");
516
517                 wispr->request = g_web_request_get(wispr->web, redirect,
518                                                         wispr_result, wispr);
519
520                 return FALSE;
521         }
522
523         printf("Message type: %s (%d)\n",
524                         message_type_to_string(wispr->msg.message_type),
525                                                 wispr->msg.message_type);
526         printf("Response code: %s (%d)\n",
527                         response_code_to_string(wispr->msg.response_code),
528                                                 wispr->msg.response_code);
529         if (wispr->msg.access_procedure != NULL)
530                 printf("Access procedure: %s\n", wispr->msg.access_procedure);
531         if (wispr->msg.access_location != NULL)
532                 printf("Access location: %s\n", wispr->msg.access_location);
533         if (wispr->msg.location_name != NULL)
534                 printf("Location name: %s\n", wispr->msg.location_name);
535         if (wispr->msg.login_url != NULL)
536                 printf("Login URL: %s\n", wispr->msg.login_url);
537         if (wispr->msg.abort_login_url != NULL)
538                 printf("Abort login URL: %s\n", wispr->msg.abort_login_url);
539         if (wispr->msg.logoff_url != NULL)
540                 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
541         printf("\n");
542
543         if (status != 200 && status != 302 && status != 404)
544                 goto done;
545
546         if (wispr->msg.message_type == 100) {
547                 if (wispr->username == NULL) {
548                         user_input("Username", FALSE, username_callback, wispr);
549                         return FALSE;
550                 }
551
552                 if (wispr->password == NULL) {
553                         user_input("Password", TRUE, password_callback, wispr);
554                         return FALSE;
555                 }
556
557                 g_idle_add(execute_login, wispr);
558                 return FALSE;
559         } else if (wispr->msg.message_type == 120 ||
560                                         wispr->msg.message_type == 140) {
561                 int code = wispr->msg.response_code;
562                 printf("Login process: %s\n",
563                                         code == 50 ? "SUCCESS" : "FAILURE");
564         }
565
566         if (status == 302) {
567                 const char *redirect;
568
569                 if (g_web_result_get_header(result, "Location",
570                                                         &redirect) == FALSE)
571                         goto done;
572
573                 printf("\n");
574                 printf("Redirect URL: %s\n", redirect);
575                 printf("\n");
576
577                 wispr->request = g_web_request_get(wispr->web, redirect,
578                                                         wispr_result, wispr);
579
580                 return FALSE;
581         }
582
583 done:
584         g_main_loop_quit(main_loop);
585
586         return FALSE;
587 }
588
589 static gboolean execute_login(gpointer user_data)
590 {
591         struct wispr_session *wispr = user_data;
592
593         wispr->request = g_web_request_post(wispr->web, wispr->msg.login_url,
594                                         "application/x-www-form-urlencoded",
595                                         wispr_input, wispr_result, wispr);
596
597         wispr_msg_init(&wispr->msg);
598
599         return FALSE;
600 }
601
602 static gboolean option_debug = FALSE;
603 static gchar *option_nameserver = NULL;
604 static gchar *option_username = NULL;
605 static gchar *option_password = NULL;
606 static gchar *option_url = NULL;
607
608 static GOptionEntry options[] = {
609         { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
610                                         "Enable debug output" },
611         { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
612                                         "Specify nameserver", "ADDRESS" },
613         { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
614                                         "Specify username", "USERNAME" },
615         { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
616                                         "Specify password", "PASSWORD" },
617         { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
618                                         "Specify arbitrary request", "URL" },
619         { NULL },
620 };
621
622 int main(int argc, char *argv[])
623 {
624         GOptionContext *context;
625         GError *error = NULL;
626         struct sigaction sa;
627         struct wispr_session wispr;
628         int index = 0;
629
630         context = g_option_context_new(NULL);
631         g_option_context_add_main_entries(context, options, NULL);
632
633         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
634                 if (error != NULL) {
635                         g_printerr("%s\n", error->message);
636                         g_error_free(error);
637                 } else
638                         g_printerr("An unknown error occurred\n");
639                 return 1;
640         }
641
642         g_option_context_free(context);
643
644         memset(&wispr, 0, sizeof(wispr));
645         wispr_msg_init(&wispr.msg);
646
647         wispr.web = g_web_new(index);
648         if (wispr.web == NULL) {
649                 fprintf(stderr, "Failed to create web service\n");
650                 return 1;
651         }
652
653         if (option_debug == TRUE)
654                 g_web_set_debug(wispr.web, web_debug, "WEB");
655
656         main_loop = g_main_loop_new(NULL, FALSE);
657
658         if (option_nameserver != NULL) {
659                 g_web_add_nameserver(wispr.web, option_nameserver);
660                 g_free(option_nameserver);
661         }
662
663         g_web_set_accept(wispr.web, NULL);
664         g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
665         g_web_set_close_connection(wispr.web, TRUE);
666
667         if (option_url == NULL)
668                 option_url = g_strdup(DEFAULT_URL);
669
670         wispr.username = option_username;
671         wispr.password = option_password;
672         wispr.originurl = option_url;
673
674         timer = g_timer_new();
675
676         wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
677                                                 "WISPAccessGatewayParam>",
678                                                 parser_callback, &wispr);
679
680         wispr.request = g_web_request_get(wispr.web, option_url,
681                                                         wispr_result, &wispr);
682
683         if (wispr.request == 0) {
684                 fprintf(stderr, "Failed to start request\n");
685                 return 1;
686         }
687
688         memset(&sa, 0, sizeof(sa));
689         sa.sa_handler = sig_term;
690         sigaction(SIGINT, &sa, NULL);
691         sigaction(SIGTERM, &sa, NULL);
692
693         g_main_loop_run(main_loop);
694
695         g_timer_destroy(timer);
696
697         if (wispr.request > 0)
698                 g_web_cancel_request(wispr.web, wispr.request);
699
700         g_web_parser_unref(wispr.parser);
701         g_web_unref(wispr.web);
702
703         g_main_loop_unref(main_loop);
704
705         g_free(wispr.username);
706         g_free(wispr.password);
707         g_free(wispr.originurl);
708
709         return 0;
710 }