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