5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
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.
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.
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
36 #include <gweb/gweb.h>
38 #define DEFAULT_URL "http://www.connman.net/online/status.html"
42 static GMainLoop *main_loop;
44 static void web_debug(const char *str, void *data)
46 g_print("%s: %s\n", (const char *) data, str);
49 static void sig_term(int sig)
51 g_main_loop_quit(main_loop);
54 static const char *message_type_to_string(int message_type)
56 switch (message_type) {
58 return "Initial redirect message";
60 return "Proxy notification";
62 return "Authentication notification";
64 return "Logoff notification";
66 return "Response to Authentication Poll";
68 return "Response to Abort Login";
74 static const char *response_code_to_string(int response_code)
76 switch (response_code) {
80 return "Login succeeded";
82 return "Login failed";
84 return "RADIUS server error/timeout";
86 return "RADIUS server not enabled";
88 return "Logoff succeeded";
90 return "Login aborted";
92 return "Proxy detection/repeat operation";
94 return "Authentication pending";
96 return "Access gateway internal error";
104 const char *current_element;
108 char *abort_login_url;
110 char *access_procedure;
111 char *access_location;
115 static inline void wispr_msg_init(struct wispr_msg *msg)
117 msg->has_error = false;
118 msg->current_element = NULL;
120 msg->message_type = -1;
121 msg->response_code = -1;
123 g_free(msg->login_url);
124 msg->login_url = NULL;
126 g_free(msg->abort_login_url);
127 msg->abort_login_url = NULL;
129 g_free(msg->logoff_url);
130 msg->logoff_url = NULL;
132 g_free(msg->access_procedure);
133 msg->access_procedure = NULL;
135 g_free(msg->access_location);
136 msg->access_location = NULL;
138 g_free(msg->location_name);
139 msg->location_name = NULL;
142 struct wispr_session {
146 struct wispr_msg msg;
153 static gboolean execute_login(gpointer user_data);
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,
168 WISPR_ELEMENT_REPLY_MESSAGE,
169 WISPR_ELEMENT_LOGIN_RESULTS_URL,
170 WISPR_ELEMENT_LOGOFF_URL,
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 },
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)
194 struct wispr_msg *msg = user_data;
196 msg->current_element = element_name;
199 static void end_element_handler(GMarkupParseContext *context,
200 const gchar *element_name,
201 gpointer user_data, GError **error)
203 struct wispr_msg *msg = user_data;
205 msg->current_element = NULL;
208 static void text_handler(GMarkupParseContext *context,
209 const gchar *text, gsize text_len,
210 gpointer user_data, GError **error)
212 struct wispr_msg *msg = user_data;
215 if (!msg->current_element)
218 for (i = 0; wispr_element_map[i].str; i++) {
219 if (!g_str_equal(wispr_element_map[i].str, msg->current_element))
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);
228 case WISPR_ELEMENT_ACCESS_LOCATION:
229 g_free(msg->access_location);
230 msg->access_location = g_strdup(text);
232 case WISPR_ELEMENT_LOCATION_NAME:
233 g_free(msg->location_name);
234 msg->location_name = g_strdup(text);
236 case WISPR_ELEMENT_LOGIN_URL:
237 g_free(msg->login_url);
238 msg->login_url = g_strdup(text);
240 case WISPR_ELEMENT_ABORT_LOGIN_URL:
241 g_free(msg->abort_login_url);
242 msg->abort_login_url = g_strdup(text);
244 case WISPR_ELEMENT_MESSAGE_TYPE:
245 msg->message_type = atoi(text);
247 case WISPR_ELEMENT_RESPONSE_CODE:
248 msg->response_code = atoi(text);
250 case WISPR_ELEMENT_NEXT_URL:
251 case WISPR_ELEMENT_DELAY:
252 case WISPR_ELEMENT_REPLY_MESSAGE:
253 case WISPR_ELEMENT_LOGIN_RESULTS_URL:
255 case WISPR_ELEMENT_LOGOFF_URL:
256 g_free(msg->logoff_url);
257 msg->logoff_url = g_strdup(text);
263 static void error_handler(GMarkupParseContext *context,
264 GError *error, gpointer user_data)
266 struct wispr_msg *msg = user_data;
268 msg->has_error = true;
271 static const GMarkupParser wispr_parser = {
272 start_element_handler,
279 static void parser_callback(const char *str, gpointer user_data)
281 struct wispr_session *wispr = user_data;
282 GMarkupParseContext *context;
285 //printf("%s\n", str);
287 context = g_markup_parse_context_new(&wispr_parser,
288 G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
290 result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
292 g_markup_parse_context_end_parse(context, NULL);
294 g_markup_parse_context_free(context);
297 typedef void (*user_input_cb)(const char *value, gpointer user_data);
299 struct user_input_data {
305 struct termios saved_termios;
308 static void user_callback(struct user_input_data *data)
315 len = write(data->fd, "\n", 1);
320 tcsetattr(data->fd, TCSADRAIN, &data->saved_termios);
324 value = g_string_free(data->str, FALSE);
327 data->cb(value, data->user_data);
334 static gboolean keyboard_input(GIOChannel *channel, GIOCondition condition,
337 struct user_input_data *data = user_data;
341 len = read(data->fd, buf, 1);
346 if (buf[0] == '\n') {
351 g_string_append_c(data->str, buf[0]);
354 len = write(data->fd, "*", 1);
359 static bool user_input(const char *label, bool hidden,
360 user_input_cb func, gpointer user_data)
362 struct user_input_data *data;
363 struct termios new_termios;
368 data = g_try_new0(struct user_input_data, 1);
372 data->str = g_string_sized_new(32);
374 data->user_data = user_data;
375 data->hidden = hidden;
377 data->fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
381 if (tcgetattr(data->fd, &data->saved_termios) < 0) {
386 new_termios = data->saved_termios;
388 new_termios.c_lflag &= ~(ICANON|ECHO);
390 new_termios.c_lflag &= ~ICANON;
391 new_termios.c_cc[VMIN] = 1;
392 new_termios.c_cc[VTIME] = 0;
394 tcsetattr(data->fd, TCSADRAIN, &new_termios);
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);
405 len = write(data->fd, label, strlen(label));
409 len = write(data->fd, ": ", 2);
416 g_string_free(data->str, TRUE);
422 static void password_callback(const char *value, gpointer user_data)
424 struct wispr_session *wispr = user_data;
426 g_free(wispr->password);
427 wispr->password = g_strdup(value);
431 execute_login(wispr);
434 static void username_callback(const char *value, gpointer user_data)
436 struct wispr_session *wispr = user_data;
438 g_free(wispr->username);
439 wispr->username = g_strdup(value);
441 if (!wispr->password) {
442 user_input("Password", true, password_callback, wispr);
448 execute_login(wispr);
451 static bool wispr_input(const guint8 **data, gsize *length,
454 struct wispr_session *wispr = user_data;
458 buf = g_string_sized_new(100);
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);
469 g_free(wispr->formdata);
470 wispr->formdata = g_string_free(buf, FALSE);
472 *data = (guint8 *) wispr->formdata;
478 static bool wispr_route(const char *addr, int ai_family, int if_index,
481 char *family = "unknown";
483 if (ai_family == AF_INET)
485 else if (ai_family == AF_INET6)
488 printf("Route request: %s %s index %d\n", family, addr, if_index);
490 if (ai_family != AF_INET && ai_family != AF_INET6)
496 static bool wispr_result(GWebResult *result, gpointer user_data)
498 struct wispr_session *wispr = user_data;
504 g_web_result_get_chunk(result, &chunk, &length);
507 //printf("%s\n", (char *) chunk);
508 g_web_parser_feed_data(wispr->parser, chunk, length);
512 g_web_parser_end_data(wispr->parser);
514 status = g_web_result_get_status(result);
516 g_print("status: %03u\n", status);
518 elapsed = g_timer_elapsed(timer, NULL);
520 g_print("elapse: %f seconds\n", elapsed);
522 if (wispr->msg.message_type < 0) {
523 const char *redirect;
528 if (!g_web_result_get_header(result, "Location", &redirect))
531 printf("Redirect URL: %s\n", redirect);
534 wispr->request = g_web_request_get(wispr->web, redirect,
535 wispr_result, wispr_route, wispr);
540 printf("Message type: %s (%d)\n",
541 message_type_to_string(wispr->msg.message_type),
542 wispr->msg.message_type);
543 printf("Response code: %s (%d)\n",
544 response_code_to_string(wispr->msg.response_code),
545 wispr->msg.response_code);
546 if (wispr->msg.access_procedure)
547 printf("Access procedure: %s\n", wispr->msg.access_procedure);
548 if (wispr->msg.access_location)
549 printf("Access location: %s\n", wispr->msg.access_location);
550 if (wispr->msg.location_name)
551 printf("Location name: %s\n", wispr->msg.location_name);
552 if (wispr->msg.login_url)
553 printf("Login URL: %s\n", wispr->msg.login_url);
554 if (wispr->msg.abort_login_url)
555 printf("Abort login URL: %s\n", wispr->msg.abort_login_url);
556 if (wispr->msg.logoff_url)
557 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
560 if (status != 200 && status != 302 && status != 404)
563 if (wispr->msg.message_type == 100) {
564 if (!wispr->username) {
565 user_input("Username", false,
566 username_callback, wispr);
570 if (!wispr->password) {
571 user_input("Password", true, password_callback, wispr);
575 g_idle_add(execute_login, wispr);
577 } else if (wispr->msg.message_type == 120 ||
578 wispr->msg.message_type == 140) {
579 int code = wispr->msg.response_code;
580 printf("Login process: %s\n",
581 code == 50 ? "SUCCESS" : "FAILURE");
585 const char *redirect;
587 if (!g_web_result_get_header(result, "Location", &redirect))
591 printf("Redirect URL: %s\n", redirect);
594 wispr->request = g_web_request_get(wispr->web, redirect,
595 wispr_result, NULL, wispr);
601 g_main_loop_quit(main_loop);
606 static gboolean execute_login(gpointer user_data)
608 struct wispr_session *wispr = user_data;
610 wispr->request = g_web_request_post(wispr->web, wispr->msg.login_url,
611 "application/x-www-form-urlencoded",
612 wispr_input, wispr_result, wispr);
614 wispr_msg_init(&wispr->msg);
619 static bool option_debug = false;
620 static gchar *option_nameserver = NULL;
621 static gchar *option_username = NULL;
622 static gchar *option_password = NULL;
623 static gchar *option_url = NULL;
625 static GOptionEntry options[] = {
626 { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
627 "Enable debug output" },
628 { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
629 "Specify nameserver", "ADDRESS" },
630 { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
631 "Specify username", "USERNAME" },
632 { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
633 "Specify password", "PASSWORD" },
634 { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
635 "Specify arbitrary request", "URL" },
639 int main(int argc, char *argv[])
641 GOptionContext *context;
642 GError *error = NULL;
644 struct wispr_session wispr;
647 context = g_option_context_new(NULL);
648 g_option_context_add_main_entries(context, options, NULL);
650 if (!g_option_context_parse(context, &argc, &argv, &error)) {
652 g_printerr("%s\n", error->message);
655 g_printerr("An unknown error occurred\n");
659 g_option_context_free(context);
661 memset(&wispr, 0, sizeof(wispr));
662 wispr_msg_init(&wispr.msg);
664 wispr.web = g_web_new(index);
666 fprintf(stderr, "Failed to create web service\n");
671 g_web_set_debug(wispr.web, web_debug, "WEB");
673 main_loop = g_main_loop_new(NULL, FALSE);
675 if (option_nameserver) {
676 g_web_add_nameserver(wispr.web, option_nameserver);
677 g_free(option_nameserver);
680 g_web_set_accept(wispr.web, NULL);
681 g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
682 g_web_set_close_connection(wispr.web, TRUE);
685 option_url = g_strdup(DEFAULT_URL);
687 wispr.username = option_username;
688 wispr.password = option_password;
689 wispr.originurl = option_url;
691 timer = g_timer_new();
693 wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
694 "WISPAccessGatewayParam>",
695 parser_callback, &wispr);
697 wispr.request = g_web_request_get(wispr.web, option_url,
698 wispr_result, wispr_route, &wispr);
700 if (wispr.request == 0) {
701 fprintf(stderr, "Failed to start request\n");
705 memset(&sa, 0, sizeof(sa));
706 sa.sa_handler = sig_term;
707 sigaction(SIGINT, &sa, NULL);
708 sigaction(SIGTERM, &sa, NULL);
710 g_main_loop_run(main_loop);
712 g_timer_destroy(timer);
714 if (wispr.request > 0)
715 g_web_cancel_request(wispr.web, wispr.request);
717 g_web_parser_unref(wispr.parser);
718 g_web_unref(wispr.web);
720 g_main_loop_unref(main_loop);
722 g_free(wispr.username);
723 g_free(wispr.password);
724 g_free(wispr.originurl);