Show provided WISPr logout URL
[platform/upstream/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 <stdlib.h>
28 #include <string.h>
29 #include <signal.h>
30
31 #include <gweb/gweb.h>
32
33 #define DEFAULT_URL  "http://www.connman.net/online/status.html"
34
35 static GTimer *timer;
36
37 static GMainLoop *main_loop;
38
39 static void web_debug(const char *str, void *data)
40 {
41         g_print("%s: %s\n", (const char *) data, str);
42 }
43
44 static void sig_term(int sig)
45 {
46         g_main_loop_quit(main_loop);
47 }
48
49 static const char *message_type_to_string(int message_type)
50 {
51         switch (message_type) {
52         case 100:
53                 return "Initial redirect message";
54         case 110:
55                 return "Proxy notification";
56         case 120:
57                 return "Authentication notification";
58         case 130:
59                 return "Logoff notification";
60         case 140:
61                 return "Response to Authentication Poll";
62         case 150:
63                 return "Response to Abort Login";
64         }
65
66         return NULL;
67 }
68
69 static const char *response_code_to_string(int response_code)
70 {
71         switch (response_code) {
72         case 0:
73                 return "No error";
74         case 50:
75                 return "Login succeeded";
76         case 100:
77                 return "Login failed";
78         case 102:
79                 return "RADIUS server error/timeout";
80         case 105:
81                 return "RADIUS server not enabled";
82         case 150:
83                 return "Logoff succeeded";
84         case 151:
85                 return "Login aborted";
86         case 200:
87                 return "Proxy detection/repeat operation";
88         case 201:
89                 return "Authentication pending";
90         case 255:
91                 return "Access gateway internal error";
92         }
93
94         return NULL;
95 }
96
97 struct wispr_msg {
98         gboolean has_error;
99         const char *current_element;
100         int message_type;
101         int response_code;
102         char *login_url;
103         char *logoff_url;
104 };
105
106 static inline void wispr_msg_init(struct wispr_msg *msg)
107 {
108         msg->has_error = FALSE;
109         msg->current_element = NULL;
110
111         msg->message_type = -1;
112         msg->response_code = -1;
113
114         g_free(msg->login_url);
115         msg->login_url = NULL;
116
117         g_free(msg->logoff_url);
118         msg->logoff_url = NULL;
119 }
120
121 struct wispr_session {
122         GWeb *web;
123         GWebParser *parser;
124         guint request;
125         struct wispr_msg msg;
126         const char *username;
127         const char *password;
128         const char *originurl;
129         char *formdata;
130 };
131
132 static struct {
133         const char *str;
134         enum {
135                 WISPR_ELEMENT_NONE,
136                 WISPR_ELEMENT_ACCESS_PROCEDURE,
137                 WISPR_ELEMENT_ACCESS_LOCATION,
138                 WISPR_ELEMENT_LOCATION_NAME,
139                 WISPR_ELEMENT_LOGIN_URL,
140                 WISPR_ELEMENT_ABORT_LOGIN_URL,
141                 WISPR_ELEMENT_MESSAGE_TYPE,
142                 WISPR_ELEMENT_RESPONSE_CODE,
143                 WISPR_ELEMENT_NEXT_URL,
144                 WISPR_ELEMENT_DELAY,
145                 WISPR_ELEMENT_REPLY_MESSAGE,
146                 WISPR_ELEMENT_LOGIN_RESULTS_URL,
147                 WISPR_ELEMENT_LOGOFF_URL,
148         } element;
149 } wispr_element_map[] = {
150         { "AccessProcedure",    WISPR_ELEMENT_ACCESS_PROCEDURE  },
151         { "AccessLocation",     WISPR_ELEMENT_ACCESS_LOCATION   },
152         { "LocationName",       WISPR_ELEMENT_LOCATION_NAME     },
153         { "LoginURL",           WISPR_ELEMENT_LOGIN_URL         },
154         { "AbortLoginURL",      WISPR_ELEMENT_ABORT_LOGIN_URL   },
155         { "MessageType",        WISPR_ELEMENT_MESSAGE_TYPE      },
156         { "ResponseCode",       WISPR_ELEMENT_RESPONSE_CODE     },
157         { "NextURL",            WISPR_ELEMENT_NEXT_URL          },
158         { "Delay",              WISPR_ELEMENT_DELAY             },
159         { "ReplyMessage",       WISPR_ELEMENT_REPLY_MESSAGE     },
160         { "LoginResultsURL",    WISPR_ELEMENT_LOGIN_RESULTS_URL },
161         { "LogoffURL",          WISPR_ELEMENT_LOGOFF_URL        },
162         { NULL,                 WISPR_ELEMENT_NONE              },
163 };
164
165 static void start_element_handler(GMarkupParseContext *context,
166                                         const gchar *element_name,
167                                         const gchar **attribute_names,
168                                         const gchar **attribute_values,
169                                         gpointer user_data, GError **error)
170 {
171         struct wispr_msg *msg = user_data;
172
173         msg->current_element = element_name;
174 }
175
176 static void end_element_handler(GMarkupParseContext *context,
177                                         const gchar *element_name,
178                                         gpointer user_data, GError **error)
179 {
180         struct wispr_msg *msg = user_data;
181
182         msg->current_element = NULL;
183 }
184
185 static void text_handler(GMarkupParseContext *context,
186                                         const gchar *text, gsize text_len,
187                                         gpointer user_data, GError **error)
188 {
189         struct wispr_msg *msg = user_data;
190         int i;
191
192         if (msg->current_element == NULL)
193                 return;
194
195         for (i = 0; wispr_element_map[i].str; i++) {
196                 if (g_str_equal(wispr_element_map[i].str,
197                                         msg->current_element) == FALSE)
198                         continue;
199
200                 switch (wispr_element_map[i].element) {
201                 case WISPR_ELEMENT_NONE:
202                 case WISPR_ELEMENT_ACCESS_PROCEDURE:
203                 case WISPR_ELEMENT_ACCESS_LOCATION:
204                 case WISPR_ELEMENT_LOCATION_NAME:
205                         break;
206                 case WISPR_ELEMENT_LOGIN_URL:
207                         g_free(msg->login_url);
208                         msg->login_url = g_strdup(text);
209                         break;
210                 case WISPR_ELEMENT_ABORT_LOGIN_URL:
211                         break;
212                 case WISPR_ELEMENT_MESSAGE_TYPE:
213                         msg->message_type = atoi(text);
214                         break;
215                 case WISPR_ELEMENT_RESPONSE_CODE:
216                         msg->response_code = atoi(text);
217                         break;
218                 case WISPR_ELEMENT_NEXT_URL:
219                 case WISPR_ELEMENT_DELAY:
220                 case WISPR_ELEMENT_REPLY_MESSAGE:
221                 case WISPR_ELEMENT_LOGIN_RESULTS_URL:
222                         break;
223                 case WISPR_ELEMENT_LOGOFF_URL:
224                         g_free(msg->logoff_url);
225                         msg->logoff_url = g_strdup(text);
226                         break;
227                 }
228         }
229 }
230
231 static void error_handler(GMarkupParseContext *context,
232                                         GError *error, gpointer user_data)
233 {
234         struct wispr_msg *msg = user_data;
235
236         msg->has_error = TRUE;
237 }
238
239 static const GMarkupParser wispr_parser = {
240         start_element_handler,
241         end_element_handler,
242         text_handler,
243         NULL,
244         error_handler,
245 };
246
247 static void parser_callback(const char *str, gpointer user_data)
248 {
249         struct wispr_session *wispr = user_data;
250         GMarkupParseContext *context;
251         gboolean result;
252
253         //printf("%s\n", str);
254
255         context = g_markup_parse_context_new(&wispr_parser,
256                         G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
257
258         result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
259         if (result == TRUE)
260                 result = g_markup_parse_context_end_parse(context, NULL);
261
262         g_markup_parse_context_free(context);
263 }
264
265 static gboolean wispr_input(const guint8 **data, gsize *length,
266                                                 gpointer user_data)
267 {
268         struct wispr_session *wispr = user_data;
269
270         g_free(wispr->formdata);
271         wispr->formdata = g_strdup_printf("button=Login&UserName=%s&"
272                         "Password=%s&FNAME=0&OriginatingServer=%s",
273                         wispr->username, wispr->password, wispr->originurl);
274
275         *data = (guint8 *) wispr->formdata;
276         *length = strlen(wispr->formdata);
277
278         return FALSE;
279 }
280
281 static gboolean wispr_result(GWebResult *result, gpointer user_data)
282 {
283         struct wispr_session *wispr = user_data;
284         const guint8 *chunk;
285         gsize length;
286         guint16 status;
287         gdouble elapsed;
288
289         g_web_result_get_chunk(result, &chunk, &length);
290
291         if (length > 0) {
292                 //printf("%s\n", (char *) chunk);
293                 g_web_parser_feed_data(wispr->parser, chunk, length);
294                 return TRUE;
295         }
296
297         g_web_parser_end_data(wispr->parser);
298
299         status = g_web_result_get_status(result);
300
301         g_print("status: %03u\n", status);
302
303         elapsed = g_timer_elapsed(timer, NULL);
304
305         g_print("elapse: %f seconds\n", elapsed);
306
307         if (wispr->msg.message_type < 0)
308                 goto done;
309
310         printf("Message type: %s (%d)\n",
311                         message_type_to_string(wispr->msg.message_type),
312                                                 wispr->msg.message_type);
313         printf("Response code: %s (%d)\n",
314                         response_code_to_string(wispr->msg.response_code),
315                                                 wispr->msg.response_code);
316         if (wispr->msg.login_url != NULL)
317                 printf("Login URL: %s\n", wispr->msg.login_url);
318         if (wispr->msg.logoff_url != NULL)
319                 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
320         printf("\n");
321
322         if (status == 302 && wispr->msg.message_type == 100) {
323                 wispr->request = g_web_request_post(wispr->web,
324                                         wispr->msg.login_url,
325                                         "application/x-www-form-urlencoded",
326                                         wispr_input, wispr_result, wispr);
327
328                 wispr_msg_init(&wispr->msg);
329
330                 return FALSE;
331         } else if (status == 200 && wispr->msg.message_type == 120) {
332                 int code = wispr->msg.response_code;
333                 printf("Login process: %s\n",
334                                         code == 50 ? "SUCCESS" : "FAILURE");
335         }
336
337 done:
338         g_main_loop_quit(main_loop);
339
340         return FALSE;
341 }
342
343 static gboolean option_debug = FALSE;
344 static gchar *option_nameserver = NULL;
345 static gchar *option_username = NULL;
346 static gchar *option_password = NULL;
347 static gchar *option_url = NULL;
348
349 static GOptionEntry options[] = {
350         { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
351                                         "Enable debug output" },
352         { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
353                                         "Specify nameserver", "ADDRESS" },
354         { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
355                                         "Specify username", "USERNAME" },
356         { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
357                                         "Specify password", "PASSWORD" },
358         { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
359                                         "Specify arbitrary request", "URL" },
360         { NULL },
361 };
362
363 int main(int argc, char *argv[])
364 {
365         GOptionContext *context;
366         GError *error = NULL;
367         struct sigaction sa;
368         struct wispr_session wispr;
369         int index = 0;
370
371         context = g_option_context_new(NULL);
372         g_option_context_add_main_entries(context, options, NULL);
373
374         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
375                 if (error != NULL) {
376                         g_printerr("%s\n", error->message);
377                         g_error_free(error);
378                 } else
379                         g_printerr("An unknown error occurred\n");
380                 return 1;
381         }
382
383         g_option_context_free(context);
384
385         memset(&wispr, 0, sizeof(wispr));
386         wispr_msg_init(&wispr.msg);
387
388         wispr.web = g_web_new(index);
389         if (wispr.web == NULL) {
390                 fprintf(stderr, "Failed to create web service\n");
391                 return 1;
392         }
393
394         if (option_debug == TRUE)
395                 g_web_set_debug(wispr.web, web_debug, "WEB");
396
397         main_loop = g_main_loop_new(NULL, FALSE);
398
399         if (option_nameserver != NULL) {
400                 g_web_add_nameserver(wispr.web, option_nameserver);
401                 g_free(option_nameserver);
402         }
403
404         g_web_set_accept(wispr.web, NULL);
405         g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
406         g_web_set_close_connection(wispr.web, TRUE);
407
408         if (option_url == NULL)
409                 option_url = g_strdup(DEFAULT_URL);
410
411         wispr.username = option_username;
412         wispr.password = option_password;
413         wispr.originurl = option_url;
414
415         timer = g_timer_new();
416
417         wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
418                                                 "WISPAccessGatewayParam>",
419                                                 parser_callback, &wispr);
420
421         wispr.request = g_web_request_get(wispr.web, option_url,
422                                                         wispr_result, &wispr);
423
424         if (wispr.request == 0) {
425                 fprintf(stderr, "Failed to start request\n");
426                 return 1;
427         }
428
429         memset(&sa, 0, sizeof(sa));
430         sa.sa_handler = sig_term;
431         sigaction(SIGINT, &sa, NULL);
432         sigaction(SIGTERM, &sa, NULL);
433
434         g_main_loop_run(main_loop);
435
436         g_timer_destroy(timer);
437
438         if (wispr.request > 0)
439                 g_web_cancel_request(wispr.web, wispr.request);
440
441         g_web_parser_unref(wispr.parser);
442         g_web_unref(wispr.web);
443
444         g_main_loop_unref(main_loop);
445
446         g_free(option_username);
447         g_free(option_password);
448         g_free(option_url);
449
450         return 0;
451 }