5 * Copyright (C) 2007-2010 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
34 #include <gweb/gweb.h>
36 #define DEFAULT_URL "http://www.connman.net/online/status.html"
40 static GMainLoop *main_loop;
42 static void web_debug(const char *str, void *data)
44 g_print("%s: %s\n", (const char *) data, str);
47 static void sig_term(int sig)
49 g_main_loop_quit(main_loop);
52 static const char *message_type_to_string(int message_type)
54 switch (message_type) {
56 return "Initial redirect message";
58 return "Proxy notification";
60 return "Authentication notification";
62 return "Logoff notification";
64 return "Response to Authentication Poll";
66 return "Response to Abort Login";
72 static const char *response_code_to_string(int response_code)
74 switch (response_code) {
78 return "Login succeeded";
80 return "Login failed";
82 return "RADIUS server error/timeout";
84 return "RADIUS server not enabled";
86 return "Logoff succeeded";
88 return "Login aborted";
90 return "Proxy detection/repeat operation";
92 return "Authentication pending";
94 return "Access gateway internal error";
102 const char *current_element;
107 char *access_procedure;
108 char *access_location;
112 static inline void wispr_msg_init(struct wispr_msg *msg)
114 msg->has_error = FALSE;
115 msg->current_element = NULL;
117 msg->message_type = -1;
118 msg->response_code = -1;
120 g_free(msg->login_url);
121 msg->login_url = NULL;
123 g_free(msg->logoff_url);
124 msg->logoff_url = NULL;
126 g_free(msg->access_procedure);
127 msg->access_procedure = NULL;
129 g_free(msg->access_location);
130 msg->access_location = NULL;
132 g_free(msg->location_name);
133 msg->location_name = NULL;
136 struct wispr_session {
140 struct wispr_msg msg;
147 static void execute_login(struct wispr_session *wispr);
153 WISPR_ELEMENT_ACCESS_PROCEDURE,
154 WISPR_ELEMENT_ACCESS_LOCATION,
155 WISPR_ELEMENT_LOCATION_NAME,
156 WISPR_ELEMENT_LOGIN_URL,
157 WISPR_ELEMENT_ABORT_LOGIN_URL,
158 WISPR_ELEMENT_MESSAGE_TYPE,
159 WISPR_ELEMENT_RESPONSE_CODE,
160 WISPR_ELEMENT_NEXT_URL,
162 WISPR_ELEMENT_REPLY_MESSAGE,
163 WISPR_ELEMENT_LOGIN_RESULTS_URL,
164 WISPR_ELEMENT_LOGOFF_URL,
166 } wispr_element_map[] = {
167 { "AccessProcedure", WISPR_ELEMENT_ACCESS_PROCEDURE },
168 { "AccessLocation", WISPR_ELEMENT_ACCESS_LOCATION },
169 { "LocationName", WISPR_ELEMENT_LOCATION_NAME },
170 { "LoginURL", WISPR_ELEMENT_LOGIN_URL },
171 { "AbortLoginURL", WISPR_ELEMENT_ABORT_LOGIN_URL },
172 { "MessageType", WISPR_ELEMENT_MESSAGE_TYPE },
173 { "ResponseCode", WISPR_ELEMENT_RESPONSE_CODE },
174 { "NextURL", WISPR_ELEMENT_NEXT_URL },
175 { "Delay", WISPR_ELEMENT_DELAY },
176 { "ReplyMessage", WISPR_ELEMENT_REPLY_MESSAGE },
177 { "LoginResultsURL", WISPR_ELEMENT_LOGIN_RESULTS_URL },
178 { "LogoffURL", WISPR_ELEMENT_LOGOFF_URL },
179 { NULL, WISPR_ELEMENT_NONE },
182 static void start_element_handler(GMarkupParseContext *context,
183 const gchar *element_name,
184 const gchar **attribute_names,
185 const gchar **attribute_values,
186 gpointer user_data, GError **error)
188 struct wispr_msg *msg = user_data;
190 msg->current_element = element_name;
193 static void end_element_handler(GMarkupParseContext *context,
194 const gchar *element_name,
195 gpointer user_data, GError **error)
197 struct wispr_msg *msg = user_data;
199 msg->current_element = NULL;
202 static void text_handler(GMarkupParseContext *context,
203 const gchar *text, gsize text_len,
204 gpointer user_data, GError **error)
206 struct wispr_msg *msg = user_data;
209 if (msg->current_element == NULL)
212 for (i = 0; wispr_element_map[i].str; i++) {
213 if (g_str_equal(wispr_element_map[i].str,
214 msg->current_element) == FALSE)
217 switch (wispr_element_map[i].element) {
218 case WISPR_ELEMENT_NONE:
219 case WISPR_ELEMENT_ACCESS_PROCEDURE:
220 g_free(msg->access_procedure);
221 msg->access_procedure = g_strdup(text);
222 case WISPR_ELEMENT_ACCESS_LOCATION:
223 g_free(msg->access_location);
224 msg->access_location = g_strdup(text);
225 case WISPR_ELEMENT_LOCATION_NAME:
226 g_free(msg->location_name);
227 msg->location_name = g_strdup(text);
229 case WISPR_ELEMENT_LOGIN_URL:
230 g_free(msg->login_url);
231 msg->login_url = g_strdup(text);
233 case WISPR_ELEMENT_ABORT_LOGIN_URL:
235 case WISPR_ELEMENT_MESSAGE_TYPE:
236 msg->message_type = atoi(text);
238 case WISPR_ELEMENT_RESPONSE_CODE:
239 msg->response_code = atoi(text);
241 case WISPR_ELEMENT_NEXT_URL:
242 case WISPR_ELEMENT_DELAY:
243 case WISPR_ELEMENT_REPLY_MESSAGE:
244 case WISPR_ELEMENT_LOGIN_RESULTS_URL:
246 case WISPR_ELEMENT_LOGOFF_URL:
247 g_free(msg->logoff_url);
248 msg->logoff_url = g_strdup(text);
254 static void error_handler(GMarkupParseContext *context,
255 GError *error, gpointer user_data)
257 struct wispr_msg *msg = user_data;
259 msg->has_error = TRUE;
262 static const GMarkupParser wispr_parser = {
263 start_element_handler,
270 static void parser_callback(const char *str, gpointer user_data)
272 struct wispr_session *wispr = user_data;
273 GMarkupParseContext *context;
276 //printf("%s\n", str);
278 context = g_markup_parse_context_new(&wispr_parser,
279 G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
281 result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
283 result = g_markup_parse_context_end_parse(context, NULL);
285 g_markup_parse_context_free(context);
288 typedef void (*user_input_cb)(const char *value, gpointer user_data);
290 struct user_input_data {
296 struct termios saved_termios;
299 static void user_callback(struct user_input_data *data)
304 if (data->hidden == TRUE)
305 len = write(data->fd, "\n", 1);
307 tcsetattr(data->fd, TCSADRAIN, &data->saved_termios);
311 value = g_string_free(data->str, FALSE);
314 data->cb(value, data->user_data);
321 static gboolean keyboard_input(GIOChannel *channel, GIOCondition condition,
324 struct user_input_data *data = user_data;
328 len = read(data->fd, buf, 1);
333 if (buf[0] == '\n') {
338 g_string_append_c(data->str, buf[0]);
343 static gboolean user_input(const char *label, gboolean hidden,
344 user_input_cb func, gpointer user_data)
346 struct user_input_data *data;
347 struct termios new_termios;
352 data = g_try_new0(struct user_input_data, 1);
356 data->str = g_string_sized_new(32);
358 data->user_data = user_data;
359 data->hidden = hidden;
361 data->fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
365 if (tcgetattr(data->fd, &data->saved_termios) < 0) {
370 new_termios = data->saved_termios;
371 if (data->hidden == TRUE)
372 new_termios.c_lflag &= ~(ICANON|ECHO);
374 new_termios.c_lflag &= ~ICANON;
375 new_termios.c_cc[VMIN] = 1;
376 new_termios.c_cc[VTIME] = 0;
378 tcsetattr(data->fd, TCSADRAIN, &new_termios);
380 channel = g_io_channel_unix_new(data->fd);
381 g_io_channel_set_encoding(channel, NULL, NULL);
382 g_io_channel_set_buffered(channel, FALSE);
383 watch = g_io_add_watch(channel, G_IO_IN, keyboard_input, data);
384 g_io_channel_unref(channel);
389 len = write(data->fd, label, strlen(label));
390 len = write(data->fd, ": ", 2);
395 g_string_free(data->str, TRUE);
401 static void password_callback(const char *value, gpointer user_data)
403 struct wispr_session *wispr = user_data;
405 g_free(wispr->password);
406 wispr->password = g_strdup(value);
410 execute_login(wispr);
413 static void username_callback(const char *value, gpointer user_data)
415 struct wispr_session *wispr = user_data;
417 g_free(wispr->username);
418 wispr->username = g_strdup(value);
420 if (wispr->password == NULL) {
421 user_input("Password", TRUE, password_callback, wispr);
427 execute_login(wispr);
430 static gboolean wispr_input(const guint8 **data, gsize *length,
433 struct wispr_session *wispr = user_data;
435 g_free(wispr->formdata);
436 wispr->formdata = g_strdup_printf("button=Login&UserName=%s&"
437 "Password=%s&FNAME=0&OriginatingServer=%s",
438 wispr->username, wispr->password, wispr->originurl);
440 *data = (guint8 *) wispr->formdata;
441 *length = strlen(wispr->formdata);
446 static gboolean wispr_result(GWebResult *result, gpointer user_data)
448 struct wispr_session *wispr = user_data;
454 g_web_result_get_chunk(result, &chunk, &length);
457 //printf("%s\n", (char *) chunk);
458 g_web_parser_feed_data(wispr->parser, chunk, length);
462 g_web_parser_end_data(wispr->parser);
464 status = g_web_result_get_status(result);
466 g_print("status: %03u\n", status);
468 elapsed = g_timer_elapsed(timer, NULL);
470 g_print("elapse: %f seconds\n", elapsed);
472 if (wispr->msg.message_type < 0)
475 printf("Message type: %s (%d)\n",
476 message_type_to_string(wispr->msg.message_type),
477 wispr->msg.message_type);
478 printf("Response code: %s (%d)\n",
479 response_code_to_string(wispr->msg.response_code),
480 wispr->msg.response_code);
481 if (wispr->msg.access_procedure != NULL)
482 printf("Access procedure: %s\n", wispr->msg.access_procedure);
483 if (wispr->msg.access_location != NULL)
484 printf("Access location: %s\n", wispr->msg.access_location);
485 if (wispr->msg.location_name != NULL)
486 printf("Location name: %s\n", wispr->msg.location_name);
487 if (wispr->msg.login_url != NULL)
488 printf("Login URL: %s\n", wispr->msg.login_url);
489 if (wispr->msg.logoff_url != NULL)
490 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
493 if (status == 302 && wispr->msg.message_type == 100) {
494 if (wispr->username == NULL) {
495 user_input("Username", FALSE, username_callback, wispr);
499 if (wispr->password == NULL) {
500 user_input("Password", TRUE, password_callback, wispr);
504 execute_login(wispr);
506 } else if (status == 200 && wispr->msg.message_type == 120) {
507 int code = wispr->msg.response_code;
508 printf("Login process: %s\n",
509 code == 50 ? "SUCCESS" : "FAILURE");
513 g_main_loop_quit(main_loop);
518 static void execute_login(struct wispr_session *wispr)
520 wispr->request = g_web_request_post(wispr->web, wispr->msg.login_url,
521 "application/x-www-form-urlencoded",
522 wispr_input, wispr_result, wispr);
524 wispr_msg_init(&wispr->msg);
527 static gboolean option_debug = FALSE;
528 static gchar *option_nameserver = NULL;
529 static gchar *option_username = NULL;
530 static gchar *option_password = NULL;
531 static gchar *option_url = NULL;
533 static GOptionEntry options[] = {
534 { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
535 "Enable debug output" },
536 { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
537 "Specify nameserver", "ADDRESS" },
538 { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
539 "Specify username", "USERNAME" },
540 { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
541 "Specify password", "PASSWORD" },
542 { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
543 "Specify arbitrary request", "URL" },
547 int main(int argc, char *argv[])
549 GOptionContext *context;
550 GError *error = NULL;
552 struct wispr_session wispr;
555 context = g_option_context_new(NULL);
556 g_option_context_add_main_entries(context, options, NULL);
558 if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
560 g_printerr("%s\n", error->message);
563 g_printerr("An unknown error occurred\n");
567 g_option_context_free(context);
569 memset(&wispr, 0, sizeof(wispr));
570 wispr_msg_init(&wispr.msg);
572 wispr.web = g_web_new(index);
573 if (wispr.web == NULL) {
574 fprintf(stderr, "Failed to create web service\n");
578 if (option_debug == TRUE)
579 g_web_set_debug(wispr.web, web_debug, "WEB");
581 main_loop = g_main_loop_new(NULL, FALSE);
583 if (option_nameserver != NULL) {
584 g_web_add_nameserver(wispr.web, option_nameserver);
585 g_free(option_nameserver);
588 g_web_set_accept(wispr.web, NULL);
589 g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
590 g_web_set_close_connection(wispr.web, TRUE);
592 if (option_url == NULL)
593 option_url = g_strdup(DEFAULT_URL);
595 wispr.username = option_username;
596 wispr.password = option_password;
597 wispr.originurl = option_url;
599 timer = g_timer_new();
601 wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
602 "WISPAccessGatewayParam>",
603 parser_callback, &wispr);
605 wispr.request = g_web_request_get(wispr.web, option_url,
606 wispr_result, &wispr);
608 if (wispr.request == 0) {
609 fprintf(stderr, "Failed to start request\n");
613 memset(&sa, 0, sizeof(sa));
614 sa.sa_handler = sig_term;
615 sigaction(SIGINT, &sa, NULL);
616 sigaction(SIGTERM, &sa, NULL);
618 g_main_loop_run(main_loop);
620 g_timer_destroy(timer);
622 if (wispr.request > 0)
623 g_web_cancel_request(wispr.web, wispr.request);
625 g_web_parser_unref(wispr.parser);
626 g_web_unref(wispr.web);
628 g_main_loop_unref(main_loop);
630 g_free(wispr.username);
631 g_free(wispr.password);
632 g_free(wispr.originurl);