Mercurial > pidgin.yaz
comparison libpurple/dnsquery.c @ 27711:7fbf964c6c6c
Move the IDN support into the DNS routines.
This turned out to be cleaner than I first thought, so here we go.
All libpurple DNS routines support IDN when built against GNU libidn.
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Sun, 19 Jul 2009 23:45:13 +0000 |
parents | 5345dfe48272 |
children | 8b669aaa3ed7 |
comparison
equal
deleted
inserted
replaced
27710:91333c6c16ef | 27711:7fbf964c6c6c |
---|---|
26 */ | 26 */ |
27 | 27 |
28 #include "internal.h" | 28 #include "internal.h" |
29 #include "debug.h" | 29 #include "debug.h" |
30 #include "dnsquery.h" | 30 #include "dnsquery.h" |
31 #include "network.h" | |
31 #include "notify.h" | 32 #include "notify.h" |
32 #include "prefs.h" | 33 #include "prefs.h" |
33 #include "util.h" | 34 #include "util.h" |
34 | 35 |
35 #ifndef _WIN32 | 36 #ifndef _WIN32 |
167 | 168 |
168 return TRUE; | 169 return TRUE; |
169 } | 170 } |
170 | 171 |
171 return FALSE; | 172 return FALSE; |
173 } | |
174 | |
175 static gboolean | |
176 dns_str_is_ascii(const char *name) | |
177 { | |
178 guchar *c; | |
179 for (c = (guchar *)name; c && *c; ++c) { | |
180 if (*c > 0x7f) | |
181 return FALSE; | |
182 } | |
183 | |
184 return TRUE; | |
172 } | 185 } |
173 | 186 |
174 #if defined(PURPLE_DNSQUERY_USE_FORK) | 187 #if defined(PURPLE_DNSQUERY_USE_FORK) |
175 | 188 |
176 /* | 189 /* |
228 char servname[20]; | 241 char servname[20]; |
229 #else | 242 #else |
230 struct sockaddr_in sin; | 243 struct sockaddr_in sin; |
231 const size_t addrlen = sizeof(sin); | 244 const size_t addrlen = sizeof(sin); |
232 #endif | 245 #endif |
246 char *hostname; | |
233 | 247 |
234 #ifdef HAVE_SIGNAL_H | 248 #ifdef HAVE_SIGNAL_H |
235 purple_restore_default_signal_handlers(); | 249 purple_restore_default_signal_handlers(); |
236 signal(SIGTRAP, trap_gdb_bug); | 250 signal(SIGTRAP, trap_gdb_bug); |
237 #endif | 251 #endif |
272 "of an empty hostname (port = %d)!!!\n", getpid(), | 286 "of an empty hostname (port = %d)!!!\n", getpid(), |
273 dns_params.port); | 287 dns_params.port); |
274 _exit(1); | 288 _exit(1); |
275 } | 289 } |
276 | 290 |
291 #ifdef USE_IDN | |
292 if (!dns_str_is_ascii(dns_params.hostname)) { | |
293 rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname); | |
294 if (rc != 0) { | |
295 write_to_parent(child_out, &rc, sizeof(rc)); | |
296 close(child_out); | |
297 if (show_debug) | |
298 fprintf(stderr, "dns[%d] Error: IDN conversion returned " | |
299 "%d\n", getpid(), rc); | |
300 dns_params.hostname[0] = '\0'; | |
301 continue; | |
302 } | |
303 } else /* intentional to execute the g_strdup */ | |
304 #endif | |
305 hostname = g_strdup(dns_params.hostname); | |
306 | |
277 /* We have the hostname and port, now resolve the IP */ | 307 /* We have the hostname and port, now resolve the IP */ |
278 | 308 |
279 #ifdef HAVE_GETADDRINFO | 309 #ifdef HAVE_GETADDRINFO |
280 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); | 310 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); |
281 memset(&hints, 0, sizeof(hints)); | 311 memset(&hints, 0, sizeof(hints)); |
288 */ | 318 */ |
289 hints.ai_socktype = SOCK_STREAM; | 319 hints.ai_socktype = SOCK_STREAM; |
290 #ifdef AI_ADDRCONFIG | 320 #ifdef AI_ADDRCONFIG |
291 hints.ai_flags |= AI_ADDRCONFIG; | 321 hints.ai_flags |= AI_ADDRCONFIG; |
292 #endif /* AI_ADDRCONFIG */ | 322 #endif /* AI_ADDRCONFIG */ |
293 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); | 323 rc = getaddrinfo(hostname, servname, &hints, &res); |
294 write_to_parent(child_out, &rc, sizeof(rc)); | 324 write_to_parent(child_out, &rc, sizeof(rc)); |
295 if (rc != 0) { | 325 if (rc != 0) { |
296 close(child_out); | 326 close(child_out); |
297 if (show_debug) | 327 if (show_debug) |
298 printf("dns[%d] Error: getaddrinfo returned %d\n", | 328 printf("dns[%d] Error: getaddrinfo returned %d\n", |
307 write_to_parent(child_out, res->ai_addr, res->ai_addrlen); | 337 write_to_parent(child_out, res->ai_addr, res->ai_addrlen); |
308 res = res->ai_next; | 338 res = res->ai_next; |
309 } | 339 } |
310 freeaddrinfo(tmp); | 340 freeaddrinfo(tmp); |
311 #else | 341 #else |
312 if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { | 342 if (!inet_aton(hostname, &sin.sin_addr)) { |
313 struct hostent *hp; | 343 struct hostent *hp; |
314 if (!(hp = gethostbyname(dns_params.hostname))) { | 344 if (!(hp = gethostbyname(hostname))) { |
315 write_to_parent(child_out, &h_errno, sizeof(int)); | 345 write_to_parent(child_out, &h_errno, sizeof(int)); |
316 close(child_out); | 346 close(child_out); |
317 if (show_debug) | 347 if (show_debug) |
318 printf("DNS Error: %d\n", h_errno); | 348 printf("DNS Error: %d\n", h_errno); |
319 _exit(0); | 349 _exit(0); |
330 write_to_parent(child_out, &addrlen, sizeof(addrlen)); | 360 write_to_parent(child_out, &addrlen, sizeof(addrlen)); |
331 write_to_parent(child_out, &sin, addrlen); | 361 write_to_parent(child_out, &sin, addrlen); |
332 #endif | 362 #endif |
333 write_to_parent(child_out, &zero, sizeof(zero)); | 363 write_to_parent(child_out, &zero, sizeof(zero)); |
334 dns_params.hostname[0] = '\0'; | 364 dns_params.hostname[0] = '\0'; |
365 | |
366 g_free(hostname); | |
367 hostname = NULL; | |
335 } | 368 } |
336 | 369 |
337 close(child_out); | 370 close(child_out); |
338 close(child_in); | 371 close(child_in); |
339 | 372 |
731 char servname[20]; | 764 char servname[20]; |
732 #else | 765 #else |
733 struct sockaddr_in sin; | 766 struct sockaddr_in sin; |
734 struct hostent *hp; | 767 struct hostent *hp; |
735 #endif | 768 #endif |
769 char *hostname; | |
736 | 770 |
737 query_data = data; | 771 query_data = data; |
772 | |
773 #ifdef USE_IDN | |
774 if (!dns_str_is_ascii(dns_params.hostname)) { | |
775 rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname); | |
776 if (rc != 0) { | |
777 /* FIXME: Dirty 2.6.0 string freeze hack */ | |
778 char tmp[8]; | |
779 g_snprintf(tmp, sizeof(tmp), "%d", rc); | |
780 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), | |
781 query_data->hostname, tmp); | |
782 /* back to main thread */ | |
783 purple_timeout_add(0, dns_main_thread_cb, query_data); | |
784 return 0; | |
785 } | |
786 } else /* intentional fallthru */ | |
787 #endif | |
788 hostname = g_strdup(dns_params.hostname); | |
738 | 789 |
739 #ifdef HAVE_GETADDRINFO | 790 #ifdef HAVE_GETADDRINFO |
740 g_snprintf(servname, sizeof(servname), "%d", query_data->port); | 791 g_snprintf(servname, sizeof(servname), "%d", query_data->port); |
741 memset(&hints,0,sizeof(hints)); | 792 memset(&hints,0,sizeof(hints)); |
742 | 793 |
749 */ | 800 */ |
750 hints.ai_socktype = SOCK_STREAM; | 801 hints.ai_socktype = SOCK_STREAM; |
751 #ifdef AI_ADDRCONFIG | 802 #ifdef AI_ADDRCONFIG |
752 hints.ai_flags |= AI_ADDRCONFIG; | 803 hints.ai_flags |= AI_ADDRCONFIG; |
753 #endif /* AI_ADDRCONFIG */ | 804 #endif /* AI_ADDRCONFIG */ |
754 if ((rc = getaddrinfo(query_data->hostname, servname, &hints, &res)) == 0) { | 805 if ((rc = getaddrinfo(hostname, servname, &hints, &res)) == 0) { |
755 tmp = res; | 806 tmp = res; |
756 while(res) { | 807 while(res) { |
757 query_data->hosts = g_slist_append(query_data->hosts, | 808 query_data->hosts = g_slist_append(query_data->hosts, |
758 GSIZE_TO_POINTER(res->ai_addrlen)); | 809 GSIZE_TO_POINTER(res->ai_addrlen)); |
759 query_data->hosts = g_slist_append(query_data->hosts, | 810 query_data->hosts = g_slist_append(query_data->hosts, |
763 freeaddrinfo(tmp); | 814 freeaddrinfo(tmp); |
764 } else { | 815 } else { |
765 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc)); | 816 query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc)); |
766 } | 817 } |
767 #else | 818 #else |
768 if ((hp = gethostbyname(query_data->hostname))) { | 819 if ((hp = gethostbyname(hostname))) { |
769 memset(&sin, 0, sizeof(struct sockaddr_in)); | 820 memset(&sin, 0, sizeof(struct sockaddr_in)); |
770 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | 821 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
771 sin.sin_family = hp->h_addrtype; | 822 sin.sin_family = hp->h_addrtype; |
772 sin.sin_port = htons(query_data->port); | 823 sin.sin_port = htons(query_data->port); |
773 | 824 |
777 g_memdup(&sin, sizeof(sin))); | 828 g_memdup(&sin, sizeof(sin))); |
778 } else { | 829 } else { |
779 query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno); | 830 query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno); |
780 } | 831 } |
781 #endif | 832 #endif |
833 g_free(hostname); | |
782 | 834 |
783 /* back to main thread */ | 835 /* back to main thread */ |
784 purple_timeout_add(0, dns_main_thread_cb, query_data); | 836 purple_timeout_add(0, dns_main_thread_cb, query_data); |
785 | 837 |
786 return 0; | 838 return 0; |
864 resolve_host(gpointer data) | 916 resolve_host(gpointer data) |
865 { | 917 { |
866 PurpleDnsQueryData *query_data; | 918 PurpleDnsQueryData *query_data; |
867 struct sockaddr_in sin; | 919 struct sockaddr_in sin; |
868 GSList *hosts = NULL; | 920 GSList *hosts = NULL; |
921 char *hostname; | |
869 | 922 |
870 query_data = data; | 923 query_data = data; |
871 query_data->timeout = 0; | 924 query_data->timeout = 0; |
872 | 925 |
873 if (purple_dnsquery_ui_resolve(query_data)) | 926 if (purple_dnsquery_ui_resolve(query_data)) |
876 return FALSE; | 929 return FALSE; |
877 } | 930 } |
878 | 931 |
879 if (!inet_aton(query_data->hostname, &sin.sin_addr)) { | 932 if (!inet_aton(query_data->hostname, &sin.sin_addr)) { |
880 struct hostent *hp; | 933 struct hostent *hp; |
881 if(!(hp = gethostbyname(query_data->hostname))) { | 934 #ifdef USE_IDN |
935 if (!dns_str_is_ascii(query_data->hostname)) { | |
936 int ret = purple_network_convert_idn_to_ascii(query_data->hostname, | |
937 &hostname); | |
938 if (ret != 0) { | |
939 char message[1024]; | |
940 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"), | |
941 query_data->hostname, ret); | |
942 purple_dnsquery_failed(query_data, message); | |
943 return FALSE; | |
944 } | |
945 } else /* fallthrough is intentional to the g_strdup */ | |
946 #endif | |
947 hostname = g_strdup(query_data->hostname); | |
948 | |
949 if(!(hp = gethostbyname(hostname))) { | |
882 char message[1024]; | 950 char message[1024]; |
883 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"), | 951 g_snprintf(message, sizeof(message), _("Error resolving %s: %d"), |
884 query_data->hostname, h_errno); | 952 query_data->hostname, h_errno); |
885 purple_dnsquery_failed(query_data, message); | 953 purple_dnsquery_failed(query_data, message); |
886 return FALSE; | 954 return FALSE; |
890 sin.sin_family = hp->h_addrtype; | 958 sin.sin_family = hp->h_addrtype; |
891 } else | 959 } else |
892 sin.sin_family = AF_INET; | 960 sin.sin_family = AF_INET; |
893 sin.sin_port = htons(query_data->port); | 961 sin.sin_port = htons(query_data->port); |
894 | 962 |
963 g_free(hostname); | |
895 hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); | 964 hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); |
896 hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); | 965 hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); |
897 | 966 |
898 purple_dnsquery_resolved(query_data, hosts); | 967 purple_dnsquery_resolved(query_data, hosts); |
899 | 968 |