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