src/util.c

changeset 7094
8f9588491993
parent 7078
0d63d673f170
child 7095
17d2b54254f8
equal deleted inserted replaced
7093:2fef5364eb2b 7094:8f9588491993
1 /* 1 /*
2 * gaim 2 * @file util.h Utility Functions
3 * @ingroup core
3 * 4 *
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> 5 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org>
5 * 7 *
6 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. 11 * (at your option) any later version.
14 * GNU General Public License for more details. 16 * GNU General Public License for more details.
15 * 17 *
16 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */ 21 */
21
22 #include "internal.h" 22 #include "internal.h"
23 23
24 #include "conversation.h" 24 #include "conversation.h"
25 #include "debug.h" 25 #include "debug.h"
26 #include "prpl.h" 26 #include "prpl.h"
27 #include "prefs.h" 27 #include "prefs.h"
28 #include "util.h"
29
30 typedef struct
31 {
32 void (*callback)(void *, const char *, size_t);
33 void *user_data;
34
35 struct
36 {
37 char *address;
38 int port;
39 char *page;
40
41 } website;
42
43 char *url;
44 gboolean full;
45 char *user_agent;
46 gboolean http11;
47
48 int inpa;
49
50 gboolean sentreq;
51 gboolean newline;
52 gboolean startsaving;
53 char *webdata;
54 unsigned long len;
55 unsigned long data_len;
56
57 } GaimFetchUrlData;
58
28 59
29 static char home_dir[MAXPATHLEN]; 60 static char home_dir[MAXPATHLEN];
30 61
31 char *full_date() 62 char *full_date()
32 { 63 {
994 1025
995 return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]); 1026 return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]);
996 } 1027 }
997 } 1028 }
998 1029
999 gboolean gaim_markup_find_tag(const char *needle, const char *haystack, const char **start, const char **end, GData **attributes) { 1030 gboolean
1031 gaim_markup_find_tag(const char *needle, const char *haystack,
1032 const char **start, const char **end, GData **attributes)
1033 {
1000 GData *attribs; 1034 GData *attribs;
1001 const char *cur = haystack; 1035 const char *cur = haystack;
1002 char *name = NULL; 1036 char *name = NULL;
1003 gboolean found = FALSE; 1037 gboolean found = FALSE;
1004 gboolean in_tag = FALSE; 1038 gboolean in_tag = FALSE;
1005 gboolean in_attr = FALSE; 1039 gboolean in_attr = FALSE;
1006 char *in_quotes = NULL; 1040 const char *in_quotes = NULL;
1007 size_t needlelen = strlen(needle); 1041 size_t needlelen = strlen(needle);
1008 1042
1009 g_datalist_init(&attribs); 1043 g_datalist_init(&attribs);
1010 1044
1011 while (*cur && !found) { 1045 while (*cur && !found) {
1131 *attributes = NULL; 1165 *attributes = NULL;
1132 } 1166 }
1133 1167
1134 return found; 1168 return found;
1135 } 1169 }
1170
1171 gboolean
1172 gaim_url_parse(const char *url, char **ret_host, int *ret_port,
1173 char **ret_path)
1174 {
1175 char scan_info[255];
1176 char port_str[5];
1177 int f;
1178 const char *turl;
1179 char host[256], path[256];
1180 int port = 0;
1181 /* hyphen at end includes it in control set */
1182 static char addr_ctrl[] = "A-Za-z0-9.-";
1183 static char port_ctrl[] = "0-9";
1184 static char page_ctrl[] = "A-Za-z0-9.~_/:*!@&%%?=+^-";
1185
1186 g_return_val_if_fail(url != NULL, FALSE);
1187
1188 if ((turl = strstr(url, "http://")) != NULL ||
1189 (turl = strstr(url, "HTTP://")) != NULL)
1190 {
1191 turl += 7;
1192 url = turl;
1193 }
1194
1195 g_snprintf(scan_info, sizeof(scan_info),
1196 "%%[%s]:%%[%s]/%%[%s]", addr_ctrl, port_ctrl, page_ctrl);
1197
1198 f = sscanf(url, scan_info, host, port_str, path);
1199
1200 if (f == 1)
1201 {
1202 g_snprintf(scan_info, sizeof(scan_info),
1203 "%%[%s]/%%[%s]",
1204 addr_ctrl, page_ctrl);
1205 f = sscanf(url, scan_info, host, path);
1206 g_snprintf(port_str, sizeof(port_str), "80");
1207 }
1208
1209 if (f == 1)
1210 *path = '\0';
1211
1212 sscanf(port_str, "%d", &port);
1213
1214 if (ret_host != NULL) *ret_host = g_strdup(host);
1215 if (ret_port != NULL) *ret_port = port;
1216 if (ret_path != NULL) *ret_path = g_strdup(path);
1217
1218 return TRUE;
1219 }
1220
1221 static void
1222 destroy_fetch_url_data(GaimFetchUrlData *gfud)
1223 {
1224 if (gfud->webdata != NULL) g_free(gfud->webdata);
1225 if (gfud->url != NULL) g_free(gfud->url);
1226 if (gfud->user_agent != NULL) g_free(gfud->user_agent);
1227 if (gfud->website.address != NULL) g_free(gfud->website.address);
1228 if (gfud->website.page != NULL) g_free(gfud->website.page);
1229
1230 g_free(gfud);
1231 }
1232
1233 static gboolean
1234 parse_redirect(const char *data, size_t data_len, gint sock,
1235 GaimFetchUrlData *gfud)
1236 {
1237 gchar *s;
1238
1239 if ((s = g_strstr_len(data, data_len, "Location: ")) != NULL)
1240 {
1241 gchar *new_url, *temp_url, *end;
1242 gboolean full;
1243 int len;
1244
1245 s += strlen("Location: ");
1246 end = strchr(s, '\r');
1247
1248 /* Just in case :) */
1249 if (end == NULL)
1250 end = strchr(s, '\n');
1251
1252 len = end - s;
1253
1254 new_url = g_malloc(len + 1);
1255 strncpy(new_url, s, len);
1256 new_url[len] = '\0';
1257
1258 full = gfud->full;
1259
1260 if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL)
1261 {
1262 temp_url = new_url;
1263
1264 new_url = g_strdup_printf("%s:%d%s", gfud->website.address,
1265 gfud->website.port, temp_url);
1266
1267 g_free(temp_url);
1268
1269 full = FALSE;
1270 }
1271
1272 /* Close the existing stuff. */
1273 gaim_input_remove(gfud->inpa);
1274 close(sock);
1275
1276 gaim_debug_info("gaim_url_fetch", "Redirecting to %s\n", new_url);
1277
1278 /* Try again, with this new location. */
1279 gaim_url_fetch(new_url, full, gfud->user_agent, gfud->http11,
1280 gfud->callback, gfud->user_data);
1281
1282 /* Free up. */
1283 g_free(new_url);
1284 destroy_fetch_url_data(gfud);
1285
1286 return TRUE;
1287 }
1288
1289 return FALSE;
1290 }
1291
1292 static size_t
1293 parse_content_len(const char *data, size_t data_len)
1294 {
1295 size_t content_len = 0;
1296
1297 sscanf(data, "Content-Length: %d", &content_len);
1298
1299 return content_len;
1300 }
1301
1302 static void
1303 url_fetched_cb(gpointer url_data, gint sock, GaimInputCondition cond)
1304 {
1305 GaimFetchUrlData *gfud = url_data;
1306 char data;
1307
1308 if (sock == -1)
1309 {
1310 gfud->callback(gfud->user_data, NULL, 0);
1311
1312 destroy_fetch_url_data(gfud);
1313
1314 return;
1315 }
1316
1317 if (!gfud->sentreq)
1318 {
1319 char buf[1024];
1320
1321 if (gfud->user_agent)
1322 {
1323 if (gfud->http11)
1324 {
1325 g_snprintf(buf, sizeof(buf),
1326 "GET %s%s HTTP/1.1\r\n"
1327 "User-Agent: \"%s\"\r\n"
1328 "Host: %s\r\n\r\n",
1329 (gfud->full ? "" : "/"),
1330 (gfud->full ? gfud->url : gfud->website.page),
1331 gfud->user_agent, gfud->website.address);
1332 }
1333 else
1334 {
1335 g_snprintf(buf, sizeof(buf),
1336 "GET %s%s HTTP/1.0\r\n"
1337 "User-Agent: \"%s\"\r\n\r\n",
1338 (gfud->full ? "" : "/"),
1339 (gfud->full ? gfud->url : gfud->website.page),
1340 gfud->user_agent);
1341 }
1342 }
1343 else
1344 {
1345 if (gfud->http11)
1346 {
1347 g_snprintf(buf, sizeof(buf),
1348 "GET %s%s HTTP/1.1\r\n"
1349 "Host: %s\r\n\r\n",
1350 (gfud->full ? "" : "/"),
1351 (gfud->full ? gfud->url : gfud->website.page),
1352 gfud->website.address);
1353 }
1354 else
1355 {
1356 g_snprintf(buf, sizeof(buf),
1357 "GET %s%s HTTP/1.0\r\n\r\n",
1358 (gfud->full ? "" : "/"),
1359 (gfud->full ? gfud->url : gfud->website.page));
1360 }
1361 }
1362
1363 gaim_debug_misc("gaim_url_fetch", "Request: %s\n", buf);
1364
1365 write(sock, buf, strlen(buf));
1366 fcntl(sock, F_SETFL, O_NONBLOCK);
1367 gfud->sentreq = TRUE;
1368 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
1369 url_fetched_cb, url_data);
1370 gfud->data_len = 4096;
1371 gfud->webdata = g_malloc(gfud->data_len);
1372
1373 return;
1374 }
1375
1376 if (read(sock, &data, 1) > 0 || errno == EWOULDBLOCK)
1377 {
1378 if (errno == EWOULDBLOCK)
1379 {
1380 errno = 0;
1381
1382 return;
1383 }
1384
1385 gfud->len++;
1386
1387 if (gfud->len == gfud->data_len + 1)
1388 {
1389 gfud->data_len += (gfud->data_len) / 2;
1390
1391 gfud->webdata = g_realloc(gfud->webdata, gfud->data_len);
1392 }
1393
1394 gfud->webdata[gfud->len - 1] = data;
1395
1396 if (!gfud->startsaving)
1397 {
1398 if (data == '\r')
1399 return;
1400
1401 if (data == '\n')
1402 {
1403 if (gfud->newline)
1404 {
1405 size_t content_len;
1406 gfud->startsaving = TRUE;
1407
1408 /* See if we can find a redirect. */
1409 if (parse_redirect(gfud->webdata, gfud->len, sock, gfud))
1410 return;
1411
1412 /* No redirect. See if we can find a content length. */
1413 content_len = parse_content_len(gfud->webdata, gfud->len);
1414
1415 if (content_len == 0)
1416 {
1417 /* We'll stick with an initial 8192 */
1418 content_len = 8192;
1419 }
1420
1421 /* Out with the old... */
1422 gfud->len = 0;
1423 g_free(gfud->webdata);
1424 gfud->webdata = NULL;
1425
1426 /* In with the new. */
1427 gfud->data_len = content_len;
1428 gfud->webdata = g_malloc(gfud->data_len);
1429 }
1430 else
1431 gfud->newline = TRUE;
1432
1433 return;
1434 }
1435
1436 gfud->newline = FALSE;
1437 }
1438 }
1439 else if (errno != ETIMEDOUT)
1440 {
1441 gfud->webdata = g_realloc(gfud->webdata, gfud->len + 1);
1442 gfud->webdata[gfud->len] = 0;
1443
1444 gaim_debug_misc("gaim_url_fetch", "Received: '%s'\n", gfud->webdata);
1445
1446 gaim_input_remove(gfud->inpa);
1447 close(sock);
1448 gfud->callback(gfud->user_data, gfud->webdata, gfud->len);
1449
1450 if (gfud->webdata)
1451 g_free(gfud->webdata);
1452
1453 destroy_fetch_url_data(gfud);
1454 }
1455 else
1456 {
1457 gaim_input_remove(gfud->inpa);
1458 close(sock);
1459
1460 gfud->callback(gfud->user_data, NULL, 0);
1461
1462 destroy_fetch_url_data(gfud);
1463 }
1464 }
1465
1466 void
1467 gaim_url_fetch(const char *url, gboolean full,
1468 const char *user_agent, gboolean http11,
1469 void (*cb)(gpointer, const char *, size_t),
1470 void *user_data)
1471 {
1472 int sock;
1473 GaimFetchUrlData *gfud;
1474
1475 g_return_if_fail(url != NULL);
1476 g_return_if_fail(cb != NULL);
1477
1478 gfud = g_new0(GaimFetchUrlData, 1);
1479
1480 gfud->callback = cb;
1481 gfud->user_data = user_data;
1482 gfud->url = g_strdup(url);
1483 gfud->user_agent = (user_agent != NULL ? g_strdup(user_agent) : NULL);
1484 gfud->http11 = http11;
1485 gfud->full = full;
1486
1487 gaim_url_parse(url, &gfud->website.address, &gfud->website.port,
1488 &gfud->website.page);
1489
1490 if ((sock = gaim_proxy_connect(NULL, gfud->website.address,
1491 gfud->website.port, url_fetched_cb,
1492 gfud)) < 0)
1493 {
1494 destroy_fetch_url_data(gfud);
1495
1496 cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0);
1497 }
1498 }

mercurial