tizen 2.4 release
[external/pacrunner.git] / libproxy / proxy.c
1 /*
2  *
3  *  libproxy - A library for proxy configuration
4  *
5  *  Copyright (C) 2010-2011  Intel Corporation. All rights reserved.
6  *
7  *  This library is free software; you can redistribute it and/or modify
8  *  it under the terms and conditions of the GNU Lesser General Public
9  *  License version 2.1 as published by the Free Software Foundation.
10  *
11  *  This library 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 Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser 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
30 #include <dbus/dbus.h>
31
32 #include "proxy.h"
33
34 struct _pxProxyFactory {
35         DBusConnection *conn;
36 };
37
38 pxProxyFactory *px_proxy_factory_new(void)
39 {
40         pxProxyFactory *factory;
41
42         factory = malloc(sizeof(*factory));
43         if (factory == NULL)
44                 return NULL;
45
46         memset(factory, 0, sizeof(*factory));
47
48         factory->conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, NULL);
49         if (factory->conn == NULL) {
50                 free(factory);
51                 return NULL;
52         }
53
54         dbus_connection_set_exit_on_disconnect(factory->conn, FALSE);
55
56         return factory;
57 }
58
59 void px_proxy_factory_free(pxProxyFactory *factory)
60 {
61         if (factory == NULL)
62                 return;
63
64         dbus_connection_close(factory->conn);
65
66         free(factory);
67 }
68
69 static char *parse_result(const char *str)
70 {
71         const char *protocol;
72         int prefix_len;
73         char *result;
74         int len = 0;
75
76         if (strcasecmp(str, "DIRECT") == 0)
77                 return strdup("direct://");
78
79         if (strncasecmp(str, "PROXY ", 6) == 0) {
80                 prefix_len = 6;
81                 protocol = "http";
82                 len = 8;
83         } else if (strncasecmp(str, "SOCKS ", 6) == 0) {
84                 prefix_len = 6;
85                 protocol = "socks";
86                 len = 9;
87         } else if (strncasecmp(str, "SOCKS4 ", 7) == 0) {
88                 prefix_len = 7;
89                 protocol = "socks4";
90                 len = 10;
91         } else if (strncasecmp(str, "SOCKS5 ", 7) == 0) {
92                 prefix_len = 7;
93                 protocol = "socks5";
94                 len = 10;
95         } else
96                 return strdup("direct://");
97
98         len = strlen(str + prefix_len) + len;
99
100         result = malloc(len);
101         if (result != NULL)
102                 sprintf(result, "%s://%s", protocol, str + prefix_len);
103
104         return result;
105 }
106
107 static char **append_result(char **prev_results, int *size, char *result)
108 {
109         char **results;
110
111         results = realloc(prev_results, sizeof(char *) * (*size + 2));
112         if (results == NULL) {
113                 free(result);
114                 return prev_results;
115         }
116
117         results[*size] = result;
118         results[*size + 1] = NULL;
119
120         *size = *size + 1;
121
122         return results;
123 }
124
125 static char **extract_results(const char *str)
126 {
127         char *copy_str, *lookup, *pos, *c, *result;
128         char **results = NULL;
129         int nb_results = 0;
130
131         copy_str = strdup(str);
132         if (copy_str == NULL)
133                 return NULL;
134
135         pos = copy_str;
136
137         while (1) {
138                 if (pos == NULL || *pos == '\0' || strlen(pos) < 6)
139                         break;
140
141                 lookup = pos;
142
143                 c = strchr(pos, ';');
144                 if (c != NULL) {
145                         for (*c = '\0', c++;
146                                 c != NULL && *c == ' '; *c = '\0', c++);
147                 }
148
149                 pos = c;
150
151                 result = parse_result(lookup);
152                 if (result != NULL)
153                         results = append_result(results, &nb_results, result);
154         }
155
156         free(copy_str);
157
158         return results;
159 }
160
161 char **px_proxy_factory_get_proxies(pxProxyFactory *factory, const char *url)
162 {
163         DBusMessage *msg, *reply;
164         const char *str = NULL;
165         char *scheme, *host, *port, *path, **result;
166
167         if (factory == NULL)
168                 return NULL;
169
170         if (url == NULL)
171                 return NULL;
172
173         msg = dbus_message_new_method_call("org.pacrunner",
174                         "/org/pacrunner/client", "org.pacrunner.Client",
175                                                         "FindProxyForURL");
176         if (msg == NULL)
177                 goto direct;
178
179         scheme = strdup(url);
180         if (scheme == NULL) {
181                 dbus_message_unref(msg);
182                 goto direct;
183         }
184
185         host = strstr(scheme, "://");
186         if (host != NULL) {
187                 *host = '\0';
188                 host += 3;
189         } else {
190                 dbus_message_unref(msg);
191                 goto direct;
192         }
193
194         path = strchr(host, '/');
195         if (path != NULL)
196                 *(path++) = '\0';
197
198         port = strrchr(host, ':');
199         if (port != NULL) {
200                 char *end;
201                 int tmp __attribute__ ((unused));
202
203                 tmp = strtol(port + 1, &end, 10);
204                 if (*end == '\0')
205                         *port = '\0';
206         }
207
208         dbus_message_append_args(msg, DBUS_TYPE_STRING, &url,
209                                 DBUS_TYPE_STRING, &host, DBUS_TYPE_INVALID);
210         free(scheme);
211
212         reply = dbus_connection_send_with_reply_and_block(factory->conn,
213                                                         msg, -1, NULL);
214
215         dbus_message_unref(msg);
216
217         if (reply == NULL)
218                 goto direct;
219
220         dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &str,
221                                                         DBUS_TYPE_INVALID);
222
223         if (str == NULL || strlen(str) == 0)
224                 str = "DIRECT";
225
226         result = extract_results(str);
227
228         dbus_message_unref(reply);
229
230         if (result == NULL)
231                 goto direct;
232
233         return result;
234
235 direct:
236         result = malloc(sizeof(char *) * 2);
237         if (result == NULL)
238                 return NULL;
239
240         result[0] = strdup("direct://");
241         result[1] = NULL;
242
243         return result;
244 }