Add login handling to WISPr command line client
[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                 case WISPR_ELEMENT_LOGOFF_URL:
223                         break;
224                 }
225         }
226 }
227
228 static void error_handler(GMarkupParseContext *context,
229                                         GError *error, gpointer user_data)
230 {
231         struct wispr_msg *msg = user_data;
232
233         msg->has_error = TRUE;
234 }
235
236 static const GMarkupParser wispr_parser = {
237         start_element_handler,
238         end_element_handler,
239         text_handler,
240         NULL,
241         error_handler,
242 };
243
244 static void parser_callback(const char *str, gpointer user_data)
245 {
246         struct wispr_session *wispr = user_data;
247         GMarkupParseContext *context;
248         gboolean result;
249
250         //printf("%s\n", str);
251
252         context = g_markup_parse_context_new(&wispr_parser,
253                         G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL);
254
255         result = g_markup_parse_context_parse(context, str, strlen(str), NULL);
256         if (result == TRUE)
257                 result = g_markup_parse_context_end_parse(context, NULL);
258
259         g_markup_parse_context_free(context);
260 }
261
262 static gboolean wispr_input(const guint8 **data, gsize *length,
263                                                 gpointer user_data)
264 {
265         struct wispr_session *wispr = user_data;
266
267         g_free(wispr->formdata);
268         wispr->formdata = g_strdup_printf("button=Login&UserName=%s&"
269                         "Password=%s&FNAME=0&OriginatingServer=%s",
270                         wispr->username, wispr->password, wispr->originurl);
271
272         *data = (guint8 *) wispr->formdata;
273         *length = strlen(wispr->formdata);
274
275         return FALSE;
276 }
277
278 static gboolean wispr_result(GWebResult *result, gpointer user_data)
279 {
280         struct wispr_session *wispr = user_data;
281         const guint8 *chunk;
282         gsize length;
283         guint16 status;
284         gdouble elapsed;
285
286         g_web_result_get_chunk(result, &chunk, &length);
287
288         if (length > 0) {
289                 //printf("%s\n", (char *) chunk);
290                 g_web_parser_feed_data(wispr->parser, chunk, length);
291                 return TRUE;
292         }
293
294         g_web_parser_end_data(wispr->parser);
295
296         status = g_web_result_get_status(result);
297
298         g_print("status: %03u\n", status);
299
300         elapsed = g_timer_elapsed(timer, NULL);
301
302         g_print("elapse: %f seconds\n", elapsed);
303
304         if (wispr->msg.message_type < 0)
305                 goto done;
306
307         printf("Message type: %s (%d)\n",
308                         message_type_to_string(wispr->msg.message_type),
309                                                 wispr->msg.message_type);
310         printf("Response code: %s (%d)\n",
311                         response_code_to_string(wispr->msg.response_code),
312                                                 wispr->msg.response_code);
313         if (wispr->msg.login_url != NULL)
314                 printf("Login URL: %s\n", wispr->msg.login_url);
315         if (wispr->msg.logoff_url != NULL)
316                 printf("Logoff URL: %s\n", wispr->msg.logoff_url);
317         printf("\n");
318
319         if (status == 302 && wispr->msg.message_type == 100) {
320                 wispr->request = g_web_request_post(wispr->web,
321                                         wispr->msg.login_url,
322                                         "application/x-www-form-urlencoded",
323                                         wispr_input, wispr_result, wispr);
324
325                 wispr_msg_init(&wispr->msg);
326
327                 return FALSE;
328         } else if (status == 200 && wispr->msg.message_type == 120) {
329                 int code = wispr->msg.response_code;
330                 printf("Login process: %s\n",
331                                         code == 50 ? "SUCCESS" : "FAILURE");
332         }
333
334 done:
335         g_main_loop_quit(main_loop);
336
337         return FALSE;
338 }
339
340 static gboolean option_debug = FALSE;
341 static gchar *option_nameserver = NULL;
342 static gchar *option_username = NULL;
343 static gchar *option_password = NULL;
344 static gchar *option_url = NULL;
345
346 static GOptionEntry options[] = {
347         { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
348                                         "Enable debug output" },
349         { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver,
350                                         "Specify nameserver", "ADDRESS" },
351         { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
352                                         "Specify username", "USERNAME" },
353         { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password,
354                                         "Specify password", "PASSWORD" },
355         { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url,
356                                         "Specify arbitrary request", "URL" },
357         { NULL },
358 };
359
360 int main(int argc, char *argv[])
361 {
362         GOptionContext *context;
363         GError *error = NULL;
364         struct sigaction sa;
365         struct wispr_session wispr;
366         int index = 0;
367
368         context = g_option_context_new(NULL);
369         g_option_context_add_main_entries(context, options, NULL);
370
371         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
372                 if (error != NULL) {
373                         g_printerr("%s\n", error->message);
374                         g_error_free(error);
375                 } else
376                         g_printerr("An unknown error occurred\n");
377                 return 1;
378         }
379
380         g_option_context_free(context);
381
382         memset(&wispr, 0, sizeof(wispr));
383         wispr_msg_init(&wispr.msg);
384
385         wispr.web = g_web_new(index);
386         if (wispr.web == NULL) {
387                 fprintf(stderr, "Failed to create web service\n");
388                 return 1;
389         }
390
391         if (option_debug == TRUE)
392                 g_web_set_debug(wispr.web, web_debug, "WEB");
393
394         main_loop = g_main_loop_new(NULL, FALSE);
395
396         if (option_nameserver != NULL) {
397                 g_web_add_nameserver(wispr.web, option_nameserver);
398                 g_free(option_nameserver);
399         }
400
401         g_web_set_accept(wispr.web, NULL);
402         g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION);
403         g_web_set_close_connection(wispr.web, TRUE);
404
405         if (option_url == NULL)
406                 option_url = g_strdup(DEFAULT_URL);
407
408         wispr.username = option_username;
409         wispr.password = option_password;
410         wispr.originurl = option_url;
411
412         timer = g_timer_new();
413
414         wispr.parser = g_web_parser_new("<WISPAccessGatewayParam",
415                                                 "WISPAccessGatewayParam>",
416                                                 parser_callback, &wispr);
417
418         wispr.request = g_web_request_get(wispr.web, option_url,
419                                                         wispr_result, &wispr);
420
421         if (wispr.request == 0) {
422                 fprintf(stderr, "Failed to start request\n");
423                 return 1;
424         }
425
426         memset(&sa, 0, sizeof(sa));
427         sa.sa_handler = sig_term;
428         sigaction(SIGINT, &sa, NULL);
429         sigaction(SIGTERM, &sa, NULL);
430
431         g_main_loop_run(main_loop);
432
433         g_timer_destroy(timer);
434
435         if (wispr.request > 0)
436                 g_web_cancel_request(wispr.web, wispr.request);
437
438         g_web_parser_unref(wispr.parser);
439         g_web_unref(wispr.web);
440
441         g_main_loop_unref(main_loop);
442
443         g_free(option_username);
444         g_free(option_password);
445         g_free(option_url);
446
447         return 0;
448 }