You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(106) |
Oct
(334) |
Nov
(246) |
Dec
(145) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(42) |
Feb
(53) |
Mar
(232) |
Apr
(109) |
May
(137) |
Jun
(63) |
Jul
(26) |
Aug
(263) |
Sep
(193) |
Oct
(507) |
Nov
(440) |
Dec
(241) |
2003 |
Jan
(567) |
Feb
(195) |
Mar
(504) |
Apr
(481) |
May
(524) |
Jun
(522) |
Jul
(594) |
Aug
(502) |
Sep
(643) |
Oct
(508) |
Nov
(430) |
Dec
(377) |
2004 |
Jan
(361) |
Feb
(251) |
Mar
(219) |
Apr
(499) |
May
(461) |
Jun
(419) |
Jul
(314) |
Aug
(519) |
Sep
(416) |
Oct
(247) |
Nov
(305) |
Dec
(382) |
2005 |
Jan
(267) |
Feb
(282) |
Mar
(327) |
Apr
(338) |
May
(189) |
Jun
(400) |
Jul
(462) |
Aug
(530) |
Sep
(316) |
Oct
(523) |
Nov
(481) |
Dec
(650) |
2006 |
Jan
(536) |
Feb
(361) |
Mar
(287) |
Apr
(146) |
May
(101) |
Jun
(169) |
Jul
(221) |
Aug
(498) |
Sep
(300) |
Oct
(236) |
Nov
(209) |
Dec
(205) |
2007 |
Jan
(30) |
Feb
(23) |
Mar
(26) |
Apr
(15) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <nos...@us...> - 2006-08-18 19:58:11
|
Revision: 16845 Author: nosnilmot Date: 2006-08-18 12:58:04 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16845&view=rev Log Message: ----------- Revision 16073: Kevin pointed out that the libgadu files aren't in EXTRA_DIST, which is necessary for building on Windows. ViewCVS Links: ------------- http://svn.sourceforge.net/gaim/?rev=16073&view=rev Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/src/protocols/gg/Makefile.am Modified: branches/v2_0_0beta3_1/gaim/src/protocols/gg/Makefile.am =================================================================== --- branches/v2_0_0beta3_1/gaim/src/protocols/gg/Makefile.am 2006-08-18 19:55:56 UTC (rev 16844) +++ branches/v2_0_0beta3_1/gaim/src/protocols/gg/Makefile.am 2006-08-18 19:58:04 UTC (rev 16845) @@ -1,4 +1,17 @@ -EXTRA_DIST = Makefile.mingw +EXTRA_DIST = \ + Makefile.mingw \ + lib/common.c \ + lib/compat.h \ + lib/COPYING \ + lib/dcc.c \ + lib/events.c \ + lib/http.c \ + lib/libgadu.c \ + lib/libgadu-config.h \ + lib/libgadu.h \ + lib/obsolete.c \ + lib/pubdir50.c \ + lib/pubdir.c pkgdir = $(libdir)/gaim This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nos...@us...> - 2006-08-18 19:56:05
|
Revision: 16844 Author: nosnilmot Date: 2006-08-18 12:55:56 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16844&view=rev Log Message: ----------- Revision 15957: Debug.xs and Signal.xs aren't being built and are missing from the dist. ViewCVS Links: ------------- http://svn.sourceforge.net/gaim/?rev=15957&view=rev Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/plugins/perl/Makefile.am Modified: branches/v2_0_0beta3_1/gaim/plugins/perl/Makefile.am =================================================================== --- branches/v2_0_0beta3_1/gaim/plugins/perl/Makefile.am 2006-08-18 19:15:05 UTC (rev 16843) +++ branches/v2_0_0beta3_1/gaim/plugins/perl/Makefile.am 2006-08-18 19:55:56 UTC (rev 16844) @@ -49,6 +49,7 @@ common/Cmds.xs \ common/Connection.xs \ common/Conversation.xs \ + common/Debug.xs \ common/FT.xs \ common/Gaim.pm \ common/Gaim.xs \ @@ -69,6 +70,7 @@ common/SSLConn.xs \ common/SavedStatuses.xs \ common/Server.xs \ + common/Signal.xs \ common/Sound.xs \ common/Status.xs \ common/Stringref.xs \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rl...@us...> - 2006-08-18 19:15:11
|
Revision: 16843 Author: rlaager Date: 2006-08-18 12:15:05 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16843&view=rev Log Message: ----------- Revision #15963: "Display the log's original timestamp on Windows. This is less confusing than my crazy crackpot idea before... AND, the logs still sort by 'real' time relative to the user." Revision #15965: "Argument order matters. Fix that last commit." ViewCVS Links: ------------- http://svn.sourceforge.net/gaim/?rev=15963&view=rev http://svn.sourceforge.net/gaim/?rev=15965&view=rev Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/src/log.c Modified: branches/v2_0_0beta3_1/gaim/src/log.c =================================================================== --- branches/v2_0_0beta3_1/gaim/src/log.c 2006-08-18 19:13:46 UTC (rev 16842) +++ branches/v2_0_0beta3_1/gaim/src/log.c 2006-08-18 19:15:05 UTC (rev 16843) @@ -698,8 +698,8 @@ { GaimLog *log; GaimLogCommonLoggerData *data; + struct tm tm; #if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE) - struct tm tm; long tz_off; const char *rest; time_t stamp = gaim_str_to_time(gaim_unescape_filename(filename), FALSE, &tm, &tz_off, &rest); @@ -722,9 +722,9 @@ g_free(tmp); } #else - time_t stamp = gaim_str_to_time(filename, FALSE, NULL, NULL, NULL); + time_t stamp = gaim_str_to_time(filename, FALSE, &tm, NULL, NULL); - log = gaim_log_new(type, name, account, NULL, stamp, NULL); + log = gaim_log_new(type, name, account, NULL, stamp, &tm); #endif log->logger = logger; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rl...@us...> - 2006-08-18 19:14:00
|
Revision: 16842 Author: rlaager Date: 2006-08-18 12:13:46 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16842&view=rev Log Message: ----------- Revision #15966: "Fix the Windows log viewer timestamps-are-off-by-my-GMT-offset bug." ViewCVS Links: ------------- http://svn.sourceforge.net/gaim/?rev=15966&view=rev Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/src/util.c Modified: branches/v2_0_0beta3_1/gaim/src/util.c =================================================================== --- branches/v2_0_0beta3_1/gaim/src/util.c 2006-08-18 19:11:18 UTC (rev 16841) +++ branches/v2_0_0beta3_1/gaim/src/util.c 2006-08-18 19:13:46 UTC (rev 16842) @@ -801,14 +801,20 @@ if (tzoff != GAIM_NO_TZ_OFF || utc) { +#if defined(_WIN32) + long sys_tzoff; +#endif + #if defined(_WIN32) || defined(HAVE_TM_GMTOFF) || defined (HAVE_TIMEZONE) if (tzoff == GAIM_NO_TZ_OFF) tzoff = 0; #endif #ifdef _WIN32 - if ((tzoff = win32_get_tz_offset()) == -1) + if ((sys_tzoff = win32_get_tz_offset()) == -1) tzoff = GAIM_NO_TZ_OFF; + else + tzoff += sys_tzoff; #else #ifdef HAVE_TM_GMTOFF tzoff += t->tm_gmtoff; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sea...@us...> - 2006-08-18 19:11:24
|
Revision: 16841 Author: seanegan Date: 2006-08-18 12:11:18 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16841&view=rev Log Message: ----------- Stu says to include this fix Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/src/proxy.c Modified: branches/v2_0_0beta3_1/gaim/src/proxy.c =================================================================== --- branches/v2_0_0beta3_1/gaim/src/proxy.c 2006-08-18 19:09:07 UTC (rev 16840) +++ branches/v2_0_0beta3_1/gaim/src/proxy.c 2006-08-18 19:11:18 UTC (rev 16841) @@ -1736,7 +1736,7 @@ { struct PHB *phb = data; int hlen = strlen(phb->host); - phb->write_buf_len = 5 + hlen + 1; + phb->write_buf_len = 5 + hlen + 2; phb->write_buffer = g_malloc(phb->write_buf_len); phb->written_len = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <may...@us...> - 2006-08-18 19:09:28
|
Revision: 16840 Author: mayuan2006 Date: 2006-08-18 12:09:07 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16840&view=rev Log Message: ----------- made for win32 develop Modified Paths: -------------- branches/soc-2006-msnp13/src/internal.h branches/soc-2006-msnp13/src/protocols/msn/Makefile.mingw branches/soc-2006-msnp13/src/win32/libc_internal.h Modified: branches/soc-2006-msnp13/src/internal.h =================================================================== --- branches/soc-2006-msnp13/src/internal.h 2006-08-18 19:03:28 UTC (rev 16839) +++ branches/soc-2006-msnp13/src/internal.h 2006-08-18 19:09:07 UTC (rev 16840) @@ -70,10 +70,10 @@ #define BUF_LONG BUF_LEN * 2 #include <sys/stat.h> -#include <sys/time.h> #include <sys/types.h> #ifndef _WIN32 #include <sys/wait.h> +#include <sys/time.h> #endif #include <ctype.h> #include <errno.h> Modified: branches/soc-2006-msnp13/src/protocols/msn/Makefile.mingw =================================================================== --- branches/soc-2006-msnp13/src/protocols/msn/Makefile.mingw 2006-08-18 19:03:28 UTC (rev 16839) +++ branches/soc-2006-msnp13/src/protocols/msn/Makefile.mingw 2006-08-18 19:09:07 UTC (rev 16840) @@ -70,6 +70,7 @@ C_SRC = cmdproc.c \ command.c \ + contact.c\ dialog.c \ directconn.c \ error.c \ @@ -81,6 +82,7 @@ nexus.c \ notification.c \ object.c \ + oim.c\ page.c \ servconn.c \ session.c \ @@ -89,6 +91,7 @@ slplink.c \ slpmsg.c \ slpsession.c \ + soap.c\ state.c \ switchboard.c \ sync.c \ Modified: branches/soc-2006-msnp13/src/win32/libc_internal.h =================================================================== --- branches/soc-2006-msnp13/src/win32/libc_internal.h 2006-08-18 19:03:28 UTC (rev 16839) +++ branches/soc-2006-msnp13/src/win32/libc_internal.h 2006-08-18 19:09:07 UTC (rev 16840) @@ -90,5 +90,4 @@ int tz_dsttime; }; - #endif /* _LIBC_INTERNAL_ */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sea...@us...> - 2006-08-18 19:03:39
|
Revision: 16839 Author: seanegan Date: 2006-08-18 12:03:28 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16839&view=rev Log Message: ----------- Anyone else have any critical bugfix changes for this? Modified Paths: -------------- branches/v2_0_0beta3_1/gaim/COPYRIGHT branches/v2_0_0beta3_1/gaim/configure.ac branches/v2_0_0beta3_1/gaim/src/gtkblist.c branches/v2_0_0beta3_1/gaim/src/protocols/msn/nexus.c Modified: branches/v2_0_0beta3_1/gaim/COPYRIGHT =================================================================== --- branches/v2_0_0beta3_1/gaim/COPYRIGHT 2006-08-18 18:47:03 UTC (rev 16838) +++ branches/v2_0_0beta3_1/gaim/COPYRIGHT 2006-08-18 19:03:28 UTC (rev 16839) @@ -292,6 +292,7 @@ David Vermeille Sid Vicious Bjoern Voigt +Wan Hing Wah Philip Walford Nathan Walp Eric Warmenhoven Modified: branches/v2_0_0beta3_1/gaim/configure.ac =================================================================== --- branches/v2_0_0beta3_1/gaim/configure.ac 2006-08-18 18:47:03 UTC (rev 16838) +++ branches/v2_0_0beta3_1/gaim/configure.ac 2006-08-18 19:03:28 UTC (rev 16839) @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([gaim], [2.0.0beta3], [gai...@li...]) +AC_INIT([gaim], [2.0.0beta3.1], [gai...@li...]) AC_CANONICAL_SYSTEM AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) Modified: branches/v2_0_0beta3_1/gaim/src/gtkblist.c =================================================================== --- branches/v2_0_0beta3_1/gaim/src/gtkblist.c 2006-08-18 18:47:03 UTC (rev 16838) +++ branches/v2_0_0beta3_1/gaim/src/gtkblist.c 2006-08-18 19:03:28 UTC (rev 16839) @@ -3422,7 +3422,7 @@ len = g_utf8_strlen(normalized, -1); log_attrs = g_new(PangoLogAttr, len + 1); - pango_get_log_attrs(normalized, len, -1, NULL, log_attrs, len + 1); + pango_get_log_attrs(normalized, strlen(normalized), -1, NULL, log_attrs, len + 1); word = normalized; result = TRUE; Modified: branches/v2_0_0beta3_1/gaim/src/protocols/msn/nexus.c =================================================================== --- branches/v2_0_0beta3_1/gaim/src/protocols/msn/nexus.c 2006-08-18 18:47:03 UTC (rev 16838) +++ branches/v2_0_0beta3_1/gaim/src/protocols/msn/nexus.c 2006-08-18 19:03:28 UTC (rev 16839) @@ -293,7 +293,16 @@ } +/* this guards against missing hash entries */ +static char * +nexus_challenge_data_lookup(GHashTable *challenge_data, const char *key) +{ + char *entry; + return (entry = (char *)g_hash_table_lookup(challenge_data, key)) ? + entry : "(null)"; +} + void login_connect_cb(gpointer data, GaimSslConnection *gsc, GaimInputCondition cond) @@ -336,16 +345,16 @@ "Host: %s\r\n" "Connection: Keep-Alive\r\n" "Cache-Control: no-cache\r\n", - (char *)g_hash_table_lookup(nexus->challenge_data, "lc"), - (char *)g_hash_table_lookup(nexus->challenge_data, "id"), - (char *)g_hash_table_lookup(nexus->challenge_data, "tw"), - (char *)g_hash_table_lookup(nexus->challenge_data, "fs"), - (char *)g_hash_table_lookup(nexus->challenge_data, "ru"), + nexus_challenge_data_lookup(nexus->challenge_data, "lc"), + nexus_challenge_data_lookup(nexus->challenge_data, "id"), + nexus_challenge_data_lookup(nexus->challenge_data, "tw"), + nexus_challenge_data_lookup(nexus->challenge_data, "fs"), + nexus_challenge_data_lookup(nexus->challenge_data, "ru"), ctint, - (char *)g_hash_table_lookup(nexus->challenge_data, "kpp"), - (char *)g_hash_table_lookup(nexus->challenge_data, "kv"), - (char *)g_hash_table_lookup(nexus->challenge_data, "ver"), - (char *)g_hash_table_lookup(nexus->challenge_data, "tpf"), + nexus_challenge_data_lookup(nexus->challenge_data, "kpp"), + nexus_challenge_data_lookup(nexus->challenge_data, "kv"), + nexus_challenge_data_lookup(nexus->challenge_data, "ver"), + nexus_challenge_data_lookup(nexus->challenge_data, "tpf"), nexus->login_host); buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sea...@us...> - 2006-08-18 18:47:16
|
Revision: 16838 Author: seanegan Date: 2006-08-18 11:47:03 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16838&view=rev Log Message: ----------- Branch for beta 3.1 Added Paths: ----------- branches/v2_0_0beta3_1/ Copied: branches/v2_0_0beta3_1 (from rev 16837, tags/v2_0_0beta3) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 09:03:36
|
Revision: 16837 Author: thekingant Date: 2006-08-18 02:03:13 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16837&view=rev Log Message: ----------- Backport SVN revisions 16833-16836 from HEAD to v2_0_0 Original commit messages: 16833: Split the DNS query code out into its own file without actually 16834: Only doing 2 DNS requests at a time seems a little restrictive. 16835: Change the DNS query function to return a struct that will eventually allow the query to be canceled. Also rename two of the DNS query things 16836: Not quite sure how I managed to do this Modified Paths: -------------- branches/v2_0_0/src/Makefile.am branches/v2_0_0/src/Makefile.mingw branches/v2_0_0/src/protocols/oscar/oscar.c branches/v2_0_0/src/protocols/simple/simple.c branches/v2_0_0/src/proxy.c branches/v2_0_0/src/proxy.h branches/v2_0_0/src/stun.c Added Paths: ----------- branches/v2_0_0/src/dnsquery.c branches/v2_0_0/src/dnsquery.h Modified: branches/v2_0_0/src/Makefile.am =================================================================== --- branches/v2_0_0/src/Makefile.am 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/Makefile.am 2006-08-18 09:03:13 UTC (rev 16837) @@ -77,6 +77,7 @@ core.c \ debug.c \ desktopitem.c \ + dnsquery.c \ eventloop.c \ ft.c \ idle.c \ @@ -125,6 +126,7 @@ dbus-maybe.h \ debug.h \ desktopitem.h \ + dnsquery.h \ eventloop.h \ ft.h \ idle.h \ Modified: branches/v2_0_0/src/Makefile.mingw =================================================================== --- branches/v2_0_0/src/Makefile.mingw 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/Makefile.mingw 2006-08-18 09:03:13 UTC (rev 16837) @@ -95,6 +95,7 @@ conversation.c \ core.c \ debug.c \ + dnsquery.c \ dnssrv.c \ eventloop.c \ ft.c \ Copied: branches/v2_0_0/src/dnsquery.c (from rev 16835, trunk/src/dnsquery.c) =================================================================== --- branches/v2_0_0/src/dnsquery.c (rev 0) +++ branches/v2_0_0/src/dnsquery.c 2006-08-18 09:03:13 UTC (rev 16837) @@ -0,0 +1,713 @@ +/** + * @file dnsquery.c DNS query API + * @ingroup core + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include "debug.h" +#include "notify.h" +#include "prefs.h" +#include "dnsquery.h" +#include "util.h" + +/************************************************************************** + * DNS query API + **************************************************************************/ + +struct _GaimDnsQueryData { +}; + +#if defined(__unix__) || defined(__APPLE__) + +#define MAX_DNS_CHILDREN 4 + +/* + * This structure represents both a pending DNS request and + * a free child process. + */ +typedef struct { + char *host; + int port; + GaimDnsQueryConnectFunction callback; + gpointer data; + guint inpa; + int fd_in, fd_out; + pid_t dns_pid; +} pending_dns_request_t; + +static GSList *free_dns_children = NULL; +static GQueue *queued_requests = NULL; + +static int number_of_dns_children = 0; + +typedef struct { + char hostname[512]; + int port; +} dns_params_t; + +typedef struct { + dns_params_t params; + GaimDnsQueryConnectFunction callback; + gpointer data; +} queued_dns_request_t; + +/* + * Begin the DNS resolver child process functions. + */ +#ifdef HAVE_SIGNAL_H +static void +trap_gdb_bug() +{ + const char *message = + "Gaim's DNS child got a SIGTRAP signal.\n" + "This can be caused by trying to run gaim inside gdb.\n" + "There is a known gdb bug which prevents this. Supposedly gaim\n" + "should have detected you were using gdb and used an ugly hack,\n" + "check cope_with_gdb_brokenness() in dnsquery.c.\n\n" + "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n"; + fputs("\n* * *\n",stderr); + fputs(message,stderr); + fputs("* * *\n\n",stderr); + execlp("xmessage","xmessage","-center", message, NULL); + _exit(1); +} +#endif + +static void +cope_with_gdb_brokenness() +{ +#ifdef __linux__ + static gboolean already_done = FALSE; + char s[256], e[512]; + int n; + pid_t ppid; + + if(already_done) + return; + already_done = TRUE; + ppid = getppid(); + snprintf(s, sizeof(s), "/proc/%d/exe", ppid); + n = readlink(s, e, sizeof(e)); + if(n < 0) + return; + + e[MIN(n,sizeof(e)-1)] = '\0'; + + if(strstr(e,"gdb")) { + gaim_debug_info("dns", + "Debugger detected, performing useless query...\n"); + gethostbyname("x.x.x.x.x"); + } +#endif +} + +static void +gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug) +{ + dns_params_t dns_params; + const size_t zero = 0; + int rc; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res, *tmp; + char servname[20]; +#else + struct sockaddr_in sin; + const size_t addrlen = sizeof(sin); +#endif + +#ifdef HAVE_SIGNAL_H + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGTRAP, trap_gdb_bug); +#endif + + /* + * We resolve 1 host name for each iteration of this + * while loop. + * + * The top half of this reads in the hostname and port + * number from the socket with our parent. The bottom + * half of this resolves the IP (blocking) and sends + * the result back to our parent, when finished. + */ + while (1) { + const char ch = 'Y'; + fd_set fds; + struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; + FD_ZERO(&fds); + FD_SET(child_in, &fds); + rc = select(child_in + 1, &fds, NULL, NULL, &tv); + if (!rc) { + if (show_debug) + printf("dns[%d]: nobody needs me... =(\n", getpid()); + break; + } + rc = read(child_in, &dns_params, sizeof(dns_params_t)); + if (rc < 0) { + perror("read()"); + break; + } + if (rc == 0) { + if (show_debug) + printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid()); + _exit(0); + } + if (dns_params.hostname[0] == '\0') { + printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); + _exit(1); + } + /* Tell our parent that we read the data successfully */ + write(child_out, &ch, sizeof(ch)); + + /* We have the hostname and port, now resolve the IP */ + +#ifdef HAVE_GETADDRINFO + g_snprintf(servname, sizeof(servname), "%d", dns_params.port); + memset(&hints, 0, sizeof(hints)); + + /* This is only used to convert a service + * name to a port number. As we know we are + * passing a number already, we know this + * value will not be really used by the C + * library. + */ + hints.ai_socktype = SOCK_STREAM; + rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); + write(child_out, &rc, sizeof(rc)); + if (rc != 0) { + close(child_out); + if (show_debug) + printf("dns[%d] Error: getaddrinfo returned %d\n", + getpid(), rc); + dns_params.hostname[0] = '\0'; + continue; + } + tmp = res; + while (res) { + size_t ai_addrlen = res->ai_addrlen; + write(child_out, &ai_addrlen, sizeof(ai_addrlen)); + write(child_out, res->ai_addr, res->ai_addrlen); + res = res->ai_next; + } + freeaddrinfo(tmp); + write(child_out, &zero, sizeof(zero)); +#else + if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { + struct hostent *hp; + if (!(hp = gethostbyname(dns_params.hostname))) { + write(child_out, &h_errno, sizeof(int)); + close(child_out); + if (show_debug) + printf("DNS Error: %d\n", h_errno); + _exit(0); + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + + sin.sin_port = htons(dns_params.port); + write(child_out, &addrlen, sizeof(addrlen)); + write(child_out, &sin, addrlen); + write(child_out, &zero, sizeof(zero)); +#endif + dns_params.hostname[0] = '\0'; + } + + close(child_out); + close(child_in); + + _exit(0); +} + +static pending_dns_request_t * +gaim_dns_new_resolverthread(gboolean show_debug) +{ + pending_dns_request_t *req; + int child_out[2], child_in[2]; + + /* Create pipes for communicating with the child process */ + if (pipe(child_out) || pipe(child_in)) { + gaim_debug_error("dns", + "Could not create pipes: %s\n", strerror(errno)); + return NULL; + } + + req = g_new(pending_dns_request_t, 1); + + cope_with_gdb_brokenness(); + + /* Fork! */ + req->dns_pid = fork(); + + /* If we are the child process... */ + if (req->dns_pid == 0) { + /* We should not access the parent's side of the pipes, so close them */ + close(child_out[0]); + close(child_in[1]); + + gaim_dns_resolverthread(child_out[1], child_in[0], show_debug); + /* The thread calls _exit() rather than returning, so we never get here */ + } + + /* We should not access the child's side of the pipes, so close them */ + close(child_out[1]); + close(child_in[0]); + if (req->dns_pid == -1) { + gaim_debug_error("dns", + "Could not create child process for DNS: %s\n", + strerror(errno)); + g_free(req); + return NULL; + } + + req->fd_out = child_out[0]; + req->fd_in = child_in[1]; + number_of_dns_children++; + gaim_debug_info("dns", + "Created new DNS child %d, there are now %d children.\n", + req->dns_pid, number_of_dns_children); + + return req; +} +/* + * End the DNS resolver child process functions. + */ + +/* + * Begin the functions for dealing with the DNS child processes. + */ +static void +req_free(pending_dns_request_t *req) +{ + g_return_if_fail(req != NULL); + + close(req->fd_in); + close(req->fd_out); + + g_free(req->host); + g_free(req); + + number_of_dns_children--; +} + +static int +send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) +{ + char ch; + int rc; + pid_t pid; + + /* This waitpid might return the child's PID if it has recently + * exited, or it might return an error if it exited "long + * enough" ago that it has already been reaped; in either + * instance, we can't use it. */ + if ((pid = waitpid (req->dns_pid, NULL, WNOHANG)) > 0) { + gaim_debug_warning("dns", + "DNS child %d no longer exists\n", req->dns_pid); + return -1; + } else if (pid < 0) { + gaim_debug_warning("dns", + "Wait for DNS child %d failed: %s\n", + req->dns_pid, strerror(errno)); + return -1; + } + + /* Let's contact this lost child! */ + rc = write(req->fd_in, dns_params, sizeof(*dns_params)); + if (rc < 0) { + gaim_debug_error("dns", + "Unable to write to DNS child %d: %d\n", + req->dns_pid, strerror(errno)); + close(req->fd_in); + return -1; + } + + g_return_val_if_fail(rc == sizeof(*dns_params), -1); + + /* Did you hear me? (This avoids some race conditions) */ + rc = read(req->fd_out, &ch, sizeof(ch)); + if (rc != 1 || ch != 'Y') + { + gaim_debug_warning("dns", + "DNS child %d not responding. Killing it!\n", + req->dns_pid); + kill(req->dns_pid, SIGKILL); + return -1; + } + + gaim_debug_info("dns", + "Successfully sent DNS request to child %d\n", req->dns_pid); + + return 0; +} + +static void +host_resolved(gpointer data, gint source, GaimInputCondition cond); + +static void +release_dns_child(pending_dns_request_t *req) +{ + g_free(req->host); + req->host = NULL; + + if (queued_requests && !g_queue_is_empty(queued_requests)) { + queued_dns_request_t *r = g_queue_pop_head(queued_requests); + req->host = g_strdup(r->params.hostname); + req->port = r->params.port; + req->callback = r->callback; + req->data = r->data; + + gaim_debug_info("dns", + "Processing queued DNS query for '%s' with child %d\n", + req->host, req->dns_pid); + + if (send_dns_request_to_child(req, &(r->params)) != 0) { + req_free(req); + req = NULL; + + gaim_debug_warning("dns", + "Intent of process queued query of '%s' failed, " + "requeueing...\n", r->params.hostname); + g_queue_push_head(queued_requests, r); + } else { + req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); + g_free(r); + } + + } else { + req->host = NULL; + req->callback = NULL; + req->data = NULL; + free_dns_children = g_slist_append(free_dns_children, req); + } +} + +static void +host_resolved(gpointer data, gint source, GaimInputCondition cond) +{ + pending_dns_request_t *req = (pending_dns_request_t*)data; + int rc, err; + GSList *hosts = NULL; + struct sockaddr *addr = NULL; + size_t addrlen; + + gaim_debug_info("dns", "Got response for '%s'\n", req->host); + gaim_input_remove(req->inpa); + + rc = read(req->fd_out, &err, sizeof(err)); + if ((rc == 4) && (err != 0)) + { + char message[1024]; +#ifdef HAVE_GETADDRINFO + g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)", + gai_strerror(err), req->dns_pid); +#else + g_snprintf(message, sizeof(message), "DNS error: %d (pid=%d)", + err, req->dns_pid); +#endif + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + release_dns_child(req); + return; + } + if (rc > 0) + { + while (rc > 0) { + rc = read(req->fd_out, &addrlen, sizeof(addrlen)); + if (rc > 0 && addrlen > 0) { + addr = g_malloc(addrlen); + rc = read(req->fd_out, addr, addrlen); + hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); + hosts = g_slist_append(hosts, addr); + } else { + break; + } + } + } else if (rc == -1) { + char message[1024]; + g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + req_free(req); + return; + } else if (rc == 0) { + char message[1024]; + g_snprintf(message, sizeof(message), "EOF reading from DNS child"); + close(req->fd_out); + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + req_free(req); + return; + } + +/* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ + + req->callback(hosts, req->data, NULL); + + release_dns_child(req); +} +/* + * End the functions for dealing with the DNS child processes. + */ + +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, GaimDnsQueryConnectFunction callback, gpointer data) +{ + pending_dns_request_t *req = NULL; + dns_params_t dns_params; + gchar *host_temp; + gboolean show_debug; + + show_debug = gaim_debug_is_enabled(); + + host_temp = g_strstrip(g_strdup(hostname)); + strncpy(dns_params.hostname, host_temp, sizeof(dns_params.hostname) - 1); + g_free(host_temp); + dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0'; + dns_params.port = port; + + /* + * If we have any children, attempt to have them perform the DNS + * query. If we're able to send the query to a child, then req + * will be set to the pending_dns_request_t. Otherwise, req will + * be NULL and we'll need to create a new DNS request child. + */ + while (free_dns_children != NULL) { + req = free_dns_children->data; + free_dns_children = g_slist_remove(free_dns_children, req); + + if (send_dns_request_to_child(req, &dns_params) == 0) + /* We found an acceptable child, yay */ + break; + + req_free(req); + req = NULL; + } + + /* We need to create a new DNS request child */ + if (req == NULL) { + if (number_of_dns_children >= MAX_DNS_CHILDREN) { + queued_dns_request_t *r = g_new(queued_dns_request_t, 1); + memcpy(&(r->params), &dns_params, sizeof(dns_params)); + r->callback = callback; + r->data = data; + if (!queued_requests) + queued_requests = g_queue_new(); + g_queue_push_tail(queued_requests, r); + + gaim_debug_info("dns", + "DNS query for '%s' queued\n", dns_params.hostname); + + return (GaimDnsQueryData *)1; + } + + req = gaim_dns_new_resolverthread(show_debug); + if (req == NULL) + { + gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n"); + return NULL; + } + send_dns_request_to_child(req, &dns_params); + } + + req->host = g_strdup(hostname); + req->port = port; + req->callback = callback; + req->data = data; + req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); + + return (GaimDnsQueryData *)1; +} + +#elif defined _WIN32 /* end __unix__ || __APPLE__ */ + +typedef struct _dns_tdata { + char *hostname; + int port; + GaimDnsQueryConnectFunction callback; + gpointer data; + GSList *hosts; + char *errmsg; +} dns_tdata; + +static gboolean dns_main_thread_cb(gpointer data) { + dns_tdata *td = (dns_tdata*)data; + if (td->errmsg != NULL) { + gaim_debug_info("dns", "%s\n", td->errmsg); + } + td->callback(td->hosts, td->data, td->errmsg); + g_free(td->hostname); + g_free(td->errmsg); + g_free(td); + return FALSE; +} + +static gpointer dns_thread(gpointer data) { + +#ifdef HAVE_GETADDRINFO + int rc; + struct addrinfo hints, *res, *tmp; + char servname[20]; +#else + struct sockaddr_in sin; + struct hostent *hp; +#endif + dns_tdata *td = (dns_tdata*)data; + +#ifdef HAVE_GETADDRINFO + g_snprintf(servname, sizeof(servname), "%d", td->port); + memset(&hints,0,sizeof(hints)); + + /* This is only used to convert a service + * name to a port number. As we know we are + * passing a number already, we know this + * value will not be really used by the C + * library. + */ + hints.ai_socktype = SOCK_STREAM; + if ((rc = getaddrinfo(td->hostname, servname, &hints, &res)) == 0) { + tmp = res; + while(res) { + td->hosts = g_slist_append(td->hosts, + GSIZE_TO_POINTER(res->ai_addrlen)); + td->hosts = g_slist_append(td->hosts, + g_memdup(res->ai_addr, res->ai_addrlen)); + res = res->ai_next; + } + freeaddrinfo(tmp); + } else { + td->errmsg = g_strdup_printf("DNS getaddrinfo(\"%s\", \"%s\") error: %d", td->hostname, servname, rc); + } +#else + if ((hp = gethostbyname(td->hostname))) { + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(td->port); + + td->hosts = g_slist_append(td->hosts, + GSIZE_TO_POINTER(sizeof(sin))); + td->hosts = g_slist_append(td->hosts, + g_memdup(&sin, sizeof(sin))); + } else { + td->errmsg = g_strdup_printf("DNS gethostbyname(\"%s\") error: %d", td->hostname, h_errno); + } +#endif + /* back to main thread */ + g_idle_add(dns_main_thread_cb, td); + return 0; +} + +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, + GaimDnsQueryConnectFunction callback, gpointer data) +{ + dns_tdata *td; + struct sockaddr_in sin; + GError* err = NULL; + + if(inet_aton(hostname, &sin.sin_addr)) { + GSList *hosts = NULL; + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); + hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); + callback(hosts, data, NULL); + return (GaimDnsQueryData *)1; + } + + gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname); + td = g_new0(dns_tdata, 1); + td->hostname = g_strdup(hostname); + td->port = port; + td->callback = callback; + td->data = data; + + if(!g_thread_create(dns_thread, td, FALSE, &err)) { + gaim_debug_error("dns", "DNS thread create failure: %s\n", err?err->message:""); + g_error_free(err); + g_free(td->hostname); + g_free(td); + return NULL; + } + return (GaimDnsQueryData *)1; +} + +#else /* not __unix__ or __APPLE__ or _WIN32 */ + +typedef struct { + gpointer data; + size_t addrlen; + struct sockaddr *addr; + GaimDnsQueryConnectFunction callback; +} pending_dns_request_t; + +static gboolean host_resolved(gpointer data) +{ + pending_dns_request_t *req = (pending_dns_request_t*)data; + GSList *hosts = NULL; + hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen)); + hosts = g_slist_append(hosts, req->addr); + req->callback(hosts, req->data, NULL); + g_free(req); + return FALSE; +} + +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, + GaimDnsQueryConnectFunction callback, gpointer data) +{ + struct sockaddr_in sin; + pending_dns_request_t *req; + + if (!inet_aton(hostname, &sin.sin_addr)) { + struct hostent *hp; + if(!(hp = gethostbyname(hostname))) { + gaim_debug_error("dns", + "gaim_gethostbyname(\"%s\", %d) failed: %d\n", + hostname, port, h_errno); + return NULL; + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + req = g_new(pending_dns_request_t, 1); + req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin)); + req->addrlen = sizeof(sin); + req->data = data; + req->callback = callback; + gaim_timeout_add(10, host_resolved, req); + return (GaimDnsQueryData *)1; +} + +#endif /* not __unix__ or __APPLE__ or _WIN32 */ Copied: branches/v2_0_0/src/dnsquery.h (from rev 16835, trunk/src/dnsquery.h) =================================================================== --- branches/v2_0_0/src/dnsquery.h (rev 0) +++ branches/v2_0_0/src/dnsquery.h 2006-08-18 09:03:13 UTC (rev 16837) @@ -0,0 +1,71 @@ +/** + * @file dnsquery.h DNS query API + * @ingroup core + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GAIM_DNSQUERY_H_ +#define _GAIM_DNSQUERY_H_ + +#include <glib.h> +#include "eventloop.h" + +typedef struct _GaimDnsQueryData GaimDnsQueryData; + +/** + * The "hosts" parameter is a linked list containing pairs of + * one size_t addrlen and one struct sockaddr *addr. + */ +typedef void (*GaimDnsQueryConnectFunction)(GSList *hosts, gpointer data, const char *error_message); + + +#include "account.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************/ +/** @name DNS query API */ +/**************************************************************************/ +/*@{*/ + +/** + * Do an async dns query + * + * @param hostname The hostname to resolve + * @param port A portnumber which is stored in the struct sockaddr + * @param callback Callback to call after resolving + * @param data Extra data for the callback function + * + * @return NULL if there was an error, otherwise return a reference to + * a data structure that can be used to cancel the pending + * DNS query, if needed. + */ +GaimDnsQueryData *gaim_dnsquery_a(const char *hostname, int port, GaimDnsQueryConnectFunction callback, gpointer data); + +/*@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _GAIM_DNSQUERY_H_ */ Modified: branches/v2_0_0/src/protocols/oscar/oscar.c =================================================================== --- branches/v2_0_0/src/protocols/oscar/oscar.c 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/protocols/oscar/oscar.c 2006-08-18 09:03:13 UTC (rev 16837) @@ -2887,7 +2887,7 @@ } else /* Set an empty message so that we know not to show "pending" */ - gaim_status_set_attr_string(status, "message", message); + gaim_status_set_attr_string(status, "message", ""); gaim_blist_update_buddy_status(b, status); } Modified: branches/v2_0_0/src/protocols/simple/simple.c =================================================================== --- branches/v2_0_0/src/protocols/simple/simple.c 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/protocols/simple/simple.c 2006-08-18 09:03:13 UTC (rev 16837) @@ -29,6 +29,7 @@ #include "accountopt.h" #include "blist.h" #include "conversation.h" +#include "dnsquery.h" #include "debug.h" #include "notify.h" #include "privacy.h" @@ -1621,7 +1622,7 @@ } else { /* UDP */ gaim_debug_info("simple", "using udp with server %s and port %d\n", hostname, port); - gaim_gethostbyname_async(hostname, port, simple_udp_host_resolved, sip); + gaim_dnsquery_a(hostname, port, simple_udp_host_resolved, sip); } } Modified: branches/v2_0_0/src/proxy.c =================================================================== --- branches/v2_0_0/src/proxy.c 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/proxy.c 2006-08-18 09:03:13 UTC (rev 16837) @@ -32,6 +32,7 @@ #include "internal.h" #include "cipher.h" #include "debug.h" +#include "dnsquery.h" #include "notify.h" #include "ntlm.h" #include "prefs.h" @@ -46,6 +47,7 @@ int fd; guint inpa; GaimProxyInfo *gpi; + GaimDnsQueryData *query_data; /** * This contains alternating length/char* values. The char* @@ -351,681 +353,7 @@ gaim_proxy_connect_info_destroy(connect_info); } -#if defined(__unix__) || defined(__APPLE__) - -/* - * This structure represents both a pending DNS request and - * a free child process. - */ -typedef struct { - char *host; - int port; - GaimProxyDnsConnectFunction callback; - gpointer data; - guint inpa; - int fd_in, fd_out; - pid_t dns_pid; -} pending_dns_request_t; - -static GSList *free_dns_children = NULL; -static GQueue *queued_requests = NULL; - -static int number_of_dns_children = 0; - -static const int MAX_DNS_CHILDREN = 2; - -typedef struct { - char hostname[512]; - int port; -} dns_params_t; - -typedef struct { - dns_params_t params; - GaimProxyDnsConnectFunction callback; - gpointer data; -} queued_dns_request_t; - -/* - * Begin the DNS resolver child process functions. - */ -#ifdef HAVE_SIGNAL_H static void -trap_gdb_bug() -{ - const char *message = - "Gaim's DNS child got a SIGTRAP signal.\n" - "This can be caused by trying to run gaim inside gdb.\n" - "There is a known gdb bug which prevents this. Supposedly gaim\n" - "should have detected you were using gdb and used an ugly hack,\n" - "check cope_with_gdb_brokenness() in proxy.c.\n\n" - "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n"; - fputs("\n* * *\n",stderr); - fputs(message,stderr); - fputs("* * *\n\n",stderr); - execlp("xmessage","xmessage","-center", message, NULL); - _exit(1); -} -#endif - -static void -cope_with_gdb_brokenness() -{ -#ifdef __linux__ - static gboolean already_done = FALSE; - char s[256], e[512]; - int n; - pid_t ppid; - - if(already_done) - return; - already_done = TRUE; - ppid = getppid(); - snprintf(s, sizeof(s), "/proc/%d/exe", ppid); - n = readlink(s, e, sizeof(e)); - if(n < 0) - return; - - e[MIN(n,sizeof(e)-1)] = '\0'; - - if(strstr(e,"gdb")) { - gaim_debug_info("dns", - "Debugger detected, performing useless query...\n"); - gethostbyname("x.x.x.x.x"); - } -#endif -} - -static void -gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug) -{ - dns_params_t dns_params; - const size_t zero = 0; - int rc; -#ifdef HAVE_GETADDRINFO - struct addrinfo hints, *res, *tmp; - char servname[20]; -#else - struct sockaddr_in sin; - const size_t addrlen = sizeof(sin); -#endif - -#ifdef HAVE_SIGNAL_H - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGTRAP, trap_gdb_bug); -#endif - - /* - * We resolve 1 host name for each iteration of this - * while loop. - * - * The top half of this reads in the hostname and port - * number from the socket with our parent. The bottom - * half of this resolves the IP (blocking) and sends - * the result back to our parent, when finished. - */ - while (1) { - const char ch = 'Y'; - fd_set fds; - struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; - FD_ZERO(&fds); - FD_SET(child_in, &fds); - rc = select(child_in + 1, &fds, NULL, NULL, &tv); - if (!rc) { - if (show_debug) - printf("dns[%d]: nobody needs me... =(\n", getpid()); - break; - } - rc = read(child_in, &dns_params, sizeof(dns_params_t)); - if (rc < 0) { - perror("read()"); - break; - } - if (rc == 0) { - if (show_debug) - printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid()); - _exit(0); - } - if (dns_params.hostname[0] == '\0') { - printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); - _exit(1); - } - /* Tell our parent that we read the data successfully */ - write(child_out, &ch, sizeof(ch)); - - /* We have the hostname and port, now resolve the IP */ - -#ifdef HAVE_GETADDRINFO - g_snprintf(servname, sizeof(servname), "%d", dns_params.port); - memset(&hints, 0, sizeof(hints)); - - /* This is only used to convert a service - * name to a port number. As we know we are - * passing a number already, we know this - * value will not be really used by the C - * library. - */ - hints.ai_socktype = SOCK_STREAM; - rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); - write(child_out, &rc, sizeof(rc)); - if (rc != 0) { - close(child_out); - if (show_debug) - printf("dns[%d] Error: getaddrinfo returned %d\n", - getpid(), rc); - dns_params.hostname[0] = '\0'; - continue; - } - tmp = res; - while (res) { - size_t ai_addrlen = res->ai_addrlen; - write(child_out, &ai_addrlen, sizeof(ai_addrlen)); - write(child_out, res->ai_addr, res->ai_addrlen); - res = res->ai_next; - } - freeaddrinfo(tmp); - write(child_out, &zero, sizeof(zero)); -#else - if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { - struct hostent *hp; - if (!(hp = gethostbyname(dns_params.hostname))) { - write(child_out, &h_errno, sizeof(int)); - close(child_out); - if (show_debug) - printf("DNS Error: %d\n", h_errno); - _exit(0); - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - - sin.sin_port = htons(dns_params.port); - write(child_out, &addrlen, sizeof(addrlen)); - write(child_out, &sin, addrlen); - write(child_out, &zero, sizeof(zero)); -#endif - dns_params.hostname[0] = '\0'; - } - - close(child_out); - close(child_in); - - _exit(0); -} - -static pending_dns_request_t * -gaim_dns_new_resolverthread(gboolean show_debug) -{ - pending_dns_request_t *req; - int child_out[2], child_in[2]; - - /* Create pipes for communicating with the child process */ - if (pipe(child_out) || pipe(child_in)) { - gaim_debug_error("dns", - "Could not create pipes: %s\n", strerror(errno)); - return NULL; - } - - req = g_new(pending_dns_request_t, 1); - - cope_with_gdb_brokenness(); - - /* Fork! */ - req->dns_pid = fork(); - - /* If we are the child process... */ - if (req->dns_pid == 0) { - /* We should not access the parent's side of the pipes, so close them */ - close(child_out[0]); - close(child_in[1]); - - gaim_dns_resolverthread(child_out[1], child_in[0], show_debug); - /* The thread calls _exit() rather than returning, so we never get here */ - } - - /* We should not access the child's side of the pipes, so close them */ - close(child_out[1]); - close(child_in[0]); - if (req->dns_pid == -1) { - gaim_debug_error("dns", - "Could not create child process for DNS: %s\n", - strerror(errno)); - g_free(req); - return NULL; - } - - req->fd_out = child_out[0]; - req->fd_in = child_in[1]; - number_of_dns_children++; - gaim_debug_info("dns", - "Created new DNS child %d, there are now %d children.\n", - req->dns_pid, number_of_dns_children); - - return req; -} -/* - * End the DNS resolver child process functions. - */ - -/* - * Begin the functions for dealing with the DNS child processes. - */ -static void -req_free(pending_dns_request_t *req) -{ - g_return_if_fail(req != NULL); - - close(req->fd_in); - close(req->fd_out); - - g_free(req->host); - g_free(req); - - number_of_dns_children--; -} - -static int -send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) -{ - char ch; - int rc; - pid_t pid; - - /* This waitpid might return the child's PID if it has recently - * exited, or it might return an error if it exited "long - * enough" ago that it has already been reaped; in either - * instance, we can't use it. */ - if ((pid = waitpid (req->dns_pid, NULL, WNOHANG)) > 0) { - gaim_debug_warning("dns", - "DNS child %d no longer exists\n", req->dns_pid); - return -1; - } else if (pid < 0) { - gaim_debug_warning("dns", - "Wait for DNS child %d failed: %s\n", - req->dns_pid, strerror(errno)); - return -1; - } - - /* Let's contact this lost child! */ - rc = write(req->fd_in, dns_params, sizeof(*dns_params)); - if (rc < 0) { - gaim_debug_error("dns", - "Unable to write to DNS child %d: %d\n", - req->dns_pid, strerror(errno)); - close(req->fd_in); - return -1; - } - - g_return_val_if_fail(rc == sizeof(*dns_params), -1); - - /* Did you hear me? (This avoids some race conditions) */ - rc = read(req->fd_out, &ch, sizeof(ch)); - if (rc != 1 || ch != 'Y') - { - gaim_debug_warning("dns", - "DNS child %d not responding. Killing it!\n", - req->dns_pid); - kill(req->dns_pid, SIGKILL); - return -1; - } - - gaim_debug_info("dns", - "Successfully sent DNS request to child %d\n", req->dns_pid); - - return 0; -} - -static void -host_resolved(gpointer data, gint source, GaimInputCondition cond); - -static void -release_dns_child(pending_dns_request_t *req) -{ - g_free(req->host); - req->host = NULL; - - if (queued_requests && !g_queue_is_empty(queued_requests)) { - queued_dns_request_t *r = g_queue_pop_head(queued_requests); - req->host = g_strdup(r->params.hostname); - req->port = r->params.port; - req->callback = r->callback; - req->data = r->data; - - gaim_debug_info("dns", - "Processing queued DNS query for '%s' with child %d\n", - req->host, req->dns_pid); - - if (send_dns_request_to_child(req, &(r->params)) != 0) { - req_free(req); - req = NULL; - - gaim_debug_warning("dns", - "Intent of process queued query of '%s' failed, " - "requeueing...\n", r->params.hostname); - g_queue_push_head(queued_requests, r); - } else { - req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); - g_free(r); - } - - } else { - req->host = NULL; - req->callback = NULL; - req->data = NULL; - free_dns_children = g_slist_append(free_dns_children, req); - } -} - -static void -host_resolved(gpointer data, gint source, GaimInputCondition cond) -{ - pending_dns_request_t *req = (pending_dns_request_t*)data; - int rc, err; - GSList *hosts = NULL; - struct sockaddr *addr = NULL; - size_t addrlen; - - gaim_debug_info("dns", "Got response for '%s'\n", req->host); - gaim_input_remove(req->inpa); - - rc = read(req->fd_out, &err, sizeof(err)); - if ((rc == 4) && (err != 0)) - { - char message[1024]; -#ifdef HAVE_GETADDRINFO - g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)", - gai_strerror(err), req->dns_pid); -#else - g_snprintf(message, sizeof(message), "DNS error: %d (pid=%d)", - err, req->dns_pid); -#endif - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - release_dns_child(req); - return; - } - if (rc > 0) - { - while (rc > 0) { - rc = read(req->fd_out, &addrlen, sizeof(addrlen)); - if (rc > 0 && addrlen > 0) { - addr = g_malloc(addrlen); - rc = read(req->fd_out, addr, addrlen); - hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); - hosts = g_slist_append(hosts, addr); - } else { - break; - } - } - } else if (rc == -1) { - char message[1024]; - g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - req_free(req); - return; - } else if (rc == 0) { - char message[1024]; - g_snprintf(message, sizeof(message), "EOF reading from DNS child"); - close(req->fd_out); - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - req_free(req); - return; - } - -/* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ - - req->callback(hosts, req->data, NULL); - - release_dns_child(req); -} -/* - * End the functions for dealing with the DNS child processes. - */ - -int -gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data) -{ - pending_dns_request_t *req = NULL; - dns_params_t dns_params; - gchar *host_temp; - gboolean show_debug; - - show_debug = gaim_debug_is_enabled(); - - host_temp = g_strstrip(g_strdup(hostname)); - strncpy(dns_params.hostname, host_temp, sizeof(dns_params.hostname) - 1); - g_free(host_temp); - dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0'; - dns_params.port = port; - - /* - * If we have any children, attempt to have them perform the DNS - * query. If we're able to send the query to a child, then req - * will be set to the pending_dns_request_t. Otherwise, req will - * be NULL and we'll need to create a new DNS request child. - */ - while (free_dns_children != NULL) { - req = free_dns_children->data; - free_dns_children = g_slist_remove(free_dns_children, req); - - if (send_dns_request_to_child(req, &dns_params) == 0) - /* We found an acceptable child, yay */ - break; - - req_free(req); - req = NULL; - } - - /* We need to create a new DNS request child */ - if (req == NULL) { - if (number_of_dns_children >= MAX_DNS_CHILDREN) { - queued_dns_request_t *r = g_new(queued_dns_request_t, 1); - memcpy(&(r->params), &dns_params, sizeof(dns_params)); - r->callback = callback; - r->data = data; - if (!queued_requests) - queued_requests = g_queue_new(); - g_queue_push_tail(queued_requests, r); - - gaim_debug_info("dns", - "DNS query for '%s' queued\n", dns_params.hostname); - - return 0; - } - - req = gaim_dns_new_resolverthread(show_debug); - if (req == NULL) - { - gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n"); - return -1; - } - send_dns_request_to_child(req, &dns_params); - } - - req->host = g_strdup(hostname); - req->port = port; - req->callback = callback; - req->data = data; - req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); - - return 0; -} - -#elif defined _WIN32 /* end __unix__ || __APPLE__ */ - -typedef struct _dns_tdata { - char *hostname; - int port; - GaimProxyDnsConnectFunction callback; - gpointer data; - GSList *hosts; - char *errmsg; -} dns_tdata; - -static gboolean dns_main_thread_cb(gpointer data) { - dns_tdata *td = (dns_tdata*)data; - if (td->errmsg != NULL) { - gaim_debug_info("dns", "%s\n", td->errmsg); - } - td->callback(td->hosts, td->data, td->errmsg); - g_free(td->hostname); - g_free(td->errmsg); - g_free(td); - return FALSE; -} - -static gpointer dns_thread(gpointer data) { - -#ifdef HAVE_GETADDRINFO - int rc; - struct addrinfo hints, *res, *tmp; - char servname[20]; -#else - struct sockaddr_in sin; - struct hostent *hp; -#endif - dns_tdata *td = (dns_tdata*)data; - -#ifdef HAVE_GETADDRINFO - g_snprintf(servname, sizeof(servname), "%d", td->port); - memset(&hints,0,sizeof(hints)); - - /* This is only used to convert a service - * name to a port number. As we know we are - * passing a number already, we know this - * value will not be really used by the C - * library. - */ - hints.ai_socktype = SOCK_STREAM; - if ((rc = getaddrinfo(td->hostname, servname, &hints, &res)) == 0) { - tmp = res; - while(res) { - td->hosts = g_slist_append(td->hosts, - GSIZE_TO_POINTER(res->ai_addrlen)); - td->hosts = g_slist_append(td->hosts, - g_memdup(res->ai_addr, res->ai_addrlen)); - res = res->ai_next; - } - freeaddrinfo(tmp); - } else { - td->errmsg = g_strdup_printf("DNS getaddrinfo(\"%s\", \"%s\") error: %d", td->hostname, servname, rc); - } -#else - if ((hp = gethostbyname(td->hostname))) { - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - sin.sin_port = htons(td->port); - - td->hosts = g_slist_append(td->hosts, - GSIZE_TO_POINTER(sizeof(sin))); - td->hosts = g_slist_append(td->hosts, - g_memdup(&sin, sizeof(sin))); - } else { - td->errmsg = g_strdup_printf("DNS gethostbyname(\"%s\") error: %d", td->hostname, h_errno); - } -#endif - /* back to main thread */ - g_idle_add(dns_main_thread_cb, td); - return 0; -} - -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) -{ - dns_tdata *td; - struct sockaddr_in sin; - GError* err = NULL; - - if(inet_aton(hostname, &sin.sin_addr)) { - GSList *hosts = NULL; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); - hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); - callback(hosts, data, NULL); - return 0; - } - - gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname); - td = g_new0(dns_tdata, 1); - td->hostname = g_strdup(hostname); - td->port = port; - td->callback = callback; - td->data = data; - - if(!g_thread_create(dns_thread, td, FALSE, &err)) { - gaim_debug_error("dns", "DNS thread create failure: %s\n", err?err->message:""); - g_error_free(err); - g_free(td->hostname); - g_free(td); - return -1; - } - return 0; -} - -#else /* not __unix__ or __APPLE__ or _WIN32 */ - -typedef struct { - gpointer data; - size_t addrlen; - struct sockaddr *addr; - GaimProxyDnsConnectFunction callback; -} pending_dns_request_t; - -static gboolean host_resolved(gpointer data) -{ - pending_dns_request_t *req = (pending_dns_request_t*)data; - GSList *hosts = NULL; - hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen)); - hosts = g_slist_append(hosts, req->addr); - req->callback(hosts, req->data, NULL); - g_free(req); - return FALSE; -} - -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) -{ - struct sockaddr_in sin; - pending_dns_request_t *req; - - if (!inet_aton(hostname, &sin.sin_addr)) { - struct hostent *hp; - if(!(hp = gethostbyname(hostname))) { - gaim_debug_error("dns", - "gaim_gethostbyname(\"%s\", %d) failed: %d\n", - hostname, port, h_errno); - return -1; - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - req = g_new(pending_dns_request_t, 1); - req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin)); - req->addrlen = sizeof(sin); - req->data = data; - req->callback = callback; - gaim_timeout_add(10, host_resolved, req); - return 0; -} - -#endif /* not __unix__ or __APPLE__ or _WIN32 */ - -static void no_one_calls(gpointer data, gint source, GaimInputCondition cond) { GaimProxyConnectInfo *connect_info = data; @@ -2368,8 +1696,9 @@ return NULL; } - if (gaim_gethostbyname_async(connecthost, - connectport, connection_host_resolved, connect_info) != 0) + connect_info->query_data = gaim_dnsquery_a(connecthost, + connectport, connection_host_resolved, connect_info); + if (connect_info->query_data == NULL) { gaim_proxy_connect_info_destroy(connect_info); return NULL; @@ -2401,8 +1730,11 @@ connect_info->port = port; connect_info->gpi = gpi; - if (gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi), - gaim_proxy_info_get_port(gpi), connection_host_resolved, connect_info) != 0) + connect_info->query_data = + gaim_dnsquery_a(gaim_proxy_info_get_host(gpi), + gaim_proxy_info_get_port(gpi), + connection_host_resolved, connect_info); + if (connect_info->query_data == NULL) { gaim_proxy_connect_info_destroy(connect_info); return NULL; Modified: branches/v2_0_0/src/proxy.h =================================================================== --- branches/v2_0_0/src/proxy.h 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/proxy.h 2006-08-18 09:03:13 UTC (rev 16837) @@ -60,13 +60,7 @@ typedef void (*GaimProxyConnectFunction)(gpointer data, gint source, const gchar *error_message); -/** - * The "hosts" parameter is a linked list containing pairs of - * one size_t addrlen and one struct sockaddr *addr. - */ -typedef void (*GaimProxyDnsConnectFunction)(GSList *hosts, gpointer data, const char *error_message); - #include "account.h" #ifdef __cplusplus @@ -278,18 +272,6 @@ */ void gaim_proxy_connect_cancel(GaimProxyConnectInfo *connect_info); -/** - * Do an async dns query - * - * @param hostname The hostname to resolve - * @param port A portnumber which is stored in the struct sockaddr - * @param callback Callback to call after resolving - * @param data Extra data for the callback function - * - * @return Zero indicates the connection is pending. Any other value indicates failure. - */ -int gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data); - /*@}*/ #ifdef __cplusplus Modified: branches/v2_0_0/src/stun.c =================================================================== --- branches/v2_0_0/src/stun.c 2006-08-18 08:55:08 UTC (rev 16836) +++ branches/v2_0_0/src/stun.c 2006-08-18 09:03:13 UTC (rev 16837) @@ -40,6 +40,7 @@ #include "debug.h" #include "account.h" +#include "dnsquery.h" #include "dnssrv.h" #include "network.h" #include "proxy.h" @@ -359,7 +360,7 @@ gaim_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n", results, servername, port); - gaim_gethostbyname_async(servername, port, hbn_cb, NULL); + gaim_dnsquery_a(servername, port, hbn_cb, NULL); g_free(resp); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 08:55:11
|
Revision: 16836 Author: thekingant Date: 2006-08-18 01:55:08 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16836&view=rev Log Message: ----------- Not quite sure how I managed to do this Modified Paths: -------------- trunk/src/protocols/oscar/oscar.c Modified: trunk/src/protocols/oscar/oscar.c =================================================================== --- trunk/src/protocols/oscar/oscar.c 2006-08-18 07:40:17 UTC (rev 16835) +++ trunk/src/protocols/oscar/oscar.c 2006-08-18 08:55:08 UTC (rev 16836) @@ -2888,7 +2888,7 @@ } else /* Set an empty message so that we know not to show "pending" */ - gaim_status_set_attr_string(status, "message", message); + gaim_status_set_attr_string(status, "message", ""); gaim_blist_update_buddy_status(b, status); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 07:40:28
|
Revision: 16835 Author: thekingant Date: 2006-08-18 00:40:17 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16835&view=rev Log Message: ----------- Change the DNS query function to return a struct that will eventually allow the query to be canceled. Also rename two of the DNS query things Modified Paths: -------------- trunk/src/dnsquery.c trunk/src/dnsquery.h trunk/src/protocols/simple/simple.c trunk/src/proxy.c trunk/src/stun.c Modified: trunk/src/dnsquery.c =================================================================== --- trunk/src/dnsquery.c 2006-08-18 07:22:55 UTC (rev 16834) +++ trunk/src/dnsquery.c 2006-08-18 07:40:17 UTC (rev 16835) @@ -35,6 +35,9 @@ * DNS query API **************************************************************************/ +struct _GaimDnsQueryData { +}; + #if defined(__unix__) || defined(__APPLE__) #define MAX_DNS_CHILDREN 4 @@ -46,7 +49,7 @@ typedef struct { char *host; int port; - GaimProxyDnsConnectFunction callback; + GaimDnsQueryConnectFunction callback; gpointer data; guint inpa; int fd_in, fd_out; @@ -65,7 +68,7 @@ typedef struct { dns_params_t params; - GaimProxyDnsConnectFunction callback; + GaimDnsQueryConnectFunction callback; gpointer data; } queued_dns_request_t; @@ -473,8 +476,8 @@ * End the functions for dealing with the DNS child processes. */ -int -gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data) +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, GaimDnsQueryConnectFunction callback, gpointer data) { pending_dns_request_t *req = NULL; dns_params_t dns_params; @@ -521,14 +524,14 @@ gaim_debug_info("dns", "DNS query for '%s' queued\n", dns_params.hostname); - return 0; + return (GaimDnsQueryData *)1; } req = gaim_dns_new_resolverthread(show_debug); if (req == NULL) { gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n"); - return -1; + return NULL; } send_dns_request_to_child(req, &dns_params); } @@ -539,7 +542,7 @@ req->data = data; req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); - return 0; + return (GaimDnsQueryData *)1; } #elif defined _WIN32 /* end __unix__ || __APPLE__ */ @@ -547,7 +550,7 @@ typedef struct _dns_tdata { char *hostname; int port; - GaimProxyDnsConnectFunction callback; + GaimDnsQueryConnectFunction callback; gpointer data; GSList *hosts; char *errmsg; @@ -621,9 +624,9 @@ return 0; } -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, + GaimDnsQueryConnectFunction callback, gpointer data) { dns_tdata *td; struct sockaddr_in sin; @@ -636,7 +639,7 @@ hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); callback(hosts, data, NULL); - return 0; + return (GaimDnsQueryData *)1; } gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname); @@ -651,9 +654,9 @@ g_error_free(err); g_free(td->hostname); g_free(td); - return -1; + return NULL; } - return 0; + return (GaimDnsQueryData *)1; } #else /* not __unix__ or __APPLE__ or _WIN32 */ @@ -662,7 +665,7 @@ gpointer data; size_t addrlen; struct sockaddr *addr; - GaimProxyDnsConnectFunction callback; + GaimDnsQueryConnectFunction callback; } pending_dns_request_t; static gboolean host_resolved(gpointer data) @@ -676,9 +679,9 @@ return FALSE; } -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) +GaimDnsQueryData * +gaim_dnsquery_a(const char *hostname, int port, + GaimDnsQueryConnectFunction callback, gpointer data) { struct sockaddr_in sin; pending_dns_request_t *req; @@ -689,7 +692,7 @@ gaim_debug_error("dns", "gaim_gethostbyname(\"%s\", %d) failed: %d\n", hostname, port, h_errno); - return -1; + return NULL; } memset(&sin, 0, sizeof(struct sockaddr_in)); memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); @@ -704,7 +707,7 @@ req->data = data; req->callback = callback; gaim_timeout_add(10, host_resolved, req); - return 0; + return (GaimDnsQueryData *)1; } #endif /* not __unix__ or __APPLE__ or _WIN32 */ Modified: trunk/src/dnsquery.h =================================================================== --- trunk/src/dnsquery.h 2006-08-18 07:22:55 UTC (rev 16834) +++ trunk/src/dnsquery.h 2006-08-18 07:40:17 UTC (rev 16835) @@ -28,11 +28,13 @@ #include <glib.h> #include "eventloop.h" +typedef struct _GaimDnsQueryData GaimDnsQueryData; + /** * The "hosts" parameter is a linked list containing pairs of * one size_t addrlen and one struct sockaddr *addr. */ -typedef void (*GaimProxyDnsConnectFunction)(GSList *hosts, gpointer data, const char *error_message); +typedef void (*GaimDnsQueryConnectFunction)(GSList *hosts, gpointer data, const char *error_message); #include "account.h" @@ -54,9 +56,11 @@ * @param callback Callback to call after resolving * @param data Extra data for the callback function * - * @return Zero indicates the connection is pending. Any other value indicates failure. + * @return NULL if there was an error, otherwise return a reference to + * a data structure that can be used to cancel the pending + * DNS query, if needed. */ -int gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data); +GaimDnsQueryData *gaim_dnsquery_a(const char *hostname, int port, GaimDnsQueryConnectFunction callback, gpointer data); /*@}*/ Modified: trunk/src/protocols/simple/simple.c =================================================================== --- trunk/src/protocols/simple/simple.c 2006-08-18 07:22:55 UTC (rev 16834) +++ trunk/src/protocols/simple/simple.c 2006-08-18 07:40:17 UTC (rev 16835) @@ -1622,7 +1622,7 @@ } else { /* UDP */ gaim_debug_info("simple", "using udp with server %s and port %d\n", hostname, port); - gaim_gethostbyname_async(hostname, port, simple_udp_host_resolved, sip); + gaim_dnsquery_a(hostname, port, simple_udp_host_resolved, sip); } } Modified: trunk/src/proxy.c =================================================================== --- trunk/src/proxy.c 2006-08-18 07:22:55 UTC (rev 16834) +++ trunk/src/proxy.c 2006-08-18 07:40:17 UTC (rev 16835) @@ -47,6 +47,7 @@ int fd; guint inpa; GaimProxyInfo *gpi; + GaimDnsQueryData *query_data; /** * This contains alternating length/char* values. The char* @@ -1695,8 +1696,9 @@ return NULL; } - if (gaim_gethostbyname_async(connecthost, - connectport, connection_host_resolved, connect_info) != 0) + connect_info->query_data = gaim_dnsquery_a(connecthost, + connectport, connection_host_resolved, connect_info); + if (connect_info->query_data == NULL) { gaim_proxy_connect_info_destroy(connect_info); return NULL; @@ -1728,8 +1730,11 @@ connect_info->port = port; connect_info->gpi = gpi; - if (gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi), - gaim_proxy_info_get_port(gpi), connection_host_resolved, connect_info) != 0) + connect_info->query_data = + gaim_dnsquery_a(gaim_proxy_info_get_host(gpi), + gaim_proxy_info_get_port(gpi), + connection_host_resolved, connect_info); + if (connect_info->query_data == NULL) { gaim_proxy_connect_info_destroy(connect_info); return NULL; Modified: trunk/src/stun.c =================================================================== --- trunk/src/stun.c 2006-08-18 07:22:55 UTC (rev 16834) +++ trunk/src/stun.c 2006-08-18 07:40:17 UTC (rev 16835) @@ -360,7 +360,7 @@ gaim_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n", results, servername, port); - gaim_gethostbyname_async(servername, port, hbn_cb, NULL); + gaim_dnsquery_a(servername, port, hbn_cb, NULL); g_free(resp); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 07:22:59
|
Revision: 16834 Author: thekingant Date: 2006-08-18 00:22:55 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16834&view=rev Log Message: ----------- Only doing 2 DNS requests at a time seems a little restrictive. Modified Paths: -------------- trunk/src/dnsquery.c Modified: trunk/src/dnsquery.c =================================================================== --- trunk/src/dnsquery.c 2006-08-18 07:20:31 UTC (rev 16833) +++ trunk/src/dnsquery.c 2006-08-18 07:22:55 UTC (rev 16834) @@ -37,6 +37,8 @@ #if defined(__unix__) || defined(__APPLE__) +#define MAX_DNS_CHILDREN 4 + /* * This structure represents both a pending DNS request and * a free child process. @@ -56,8 +58,6 @@ static int number_of_dns_children = 0; -static const int MAX_DNS_CHILDREN = 2; - typedef struct { char hostname[512]; int port; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 07:20:42
|
Revision: 16833 Author: thekingant Date: 2006-08-18 00:20:31 -0700 (Fri, 18 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16833&view=rev Log Message: ----------- Split the DNS query code out into its own file without actually changing anything. Modified Paths: -------------- trunk/src/Makefile.am trunk/src/Makefile.mingw trunk/src/protocols/simple/simple.c trunk/src/proxy.c trunk/src/proxy.h trunk/src/stun.c Added Paths: ----------- trunk/src/dnsquery.c trunk/src/dnsquery.h Modified: trunk/src/Makefile.am =================================================================== --- trunk/src/Makefile.am 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/Makefile.am 2006-08-18 07:20:31 UTC (rev 16833) @@ -77,6 +77,7 @@ core.c \ debug.c \ desktopitem.c \ + dnsquery.c \ eventloop.c \ ft.c \ idle.c \ @@ -125,6 +126,7 @@ dbus-maybe.h \ debug.h \ desktopitem.h \ + dnsquery.h \ eventloop.h \ ft.h \ idle.h \ Modified: trunk/src/Makefile.mingw =================================================================== --- trunk/src/Makefile.mingw 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/Makefile.mingw 2006-08-18 07:20:31 UTC (rev 16833) @@ -95,6 +95,7 @@ conversation.c \ core.c \ debug.c \ + dnsquery.c \ dnssrv.c \ eventloop.c \ ft.c \ Added: trunk/src/dnsquery.c =================================================================== --- trunk/src/dnsquery.c (rev 0) +++ trunk/src/dnsquery.c 2006-08-18 07:20:31 UTC (rev 16833) @@ -0,0 +1,710 @@ +/** + * @file dnsquery.c DNS query API + * @ingroup core + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include "debug.h" +#include "notify.h" +#include "prefs.h" +#include "dnsquery.h" +#include "util.h" + +/************************************************************************** + * DNS query API + **************************************************************************/ + +#if defined(__unix__) || defined(__APPLE__) + +/* + * This structure represents both a pending DNS request and + * a free child process. + */ +typedef struct { + char *host; + int port; + GaimProxyDnsConnectFunction callback; + gpointer data; + guint inpa; + int fd_in, fd_out; + pid_t dns_pid; +} pending_dns_request_t; + +static GSList *free_dns_children = NULL; +static GQueue *queued_requests = NULL; + +static int number_of_dns_children = 0; + +static const int MAX_DNS_CHILDREN = 2; + +typedef struct { + char hostname[512]; + int port; +} dns_params_t; + +typedef struct { + dns_params_t params; + GaimProxyDnsConnectFunction callback; + gpointer data; +} queued_dns_request_t; + +/* + * Begin the DNS resolver child process functions. + */ +#ifdef HAVE_SIGNAL_H +static void +trap_gdb_bug() +{ + const char *message = + "Gaim's DNS child got a SIGTRAP signal.\n" + "This can be caused by trying to run gaim inside gdb.\n" + "There is a known gdb bug which prevents this. Supposedly gaim\n" + "should have detected you were using gdb and used an ugly hack,\n" + "check cope_with_gdb_brokenness() in dnsquery.c.\n\n" + "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n"; + fputs("\n* * *\n",stderr); + fputs(message,stderr); + fputs("* * *\n\n",stderr); + execlp("xmessage","xmessage","-center", message, NULL); + _exit(1); +} +#endif + +static void +cope_with_gdb_brokenness() +{ +#ifdef __linux__ + static gboolean already_done = FALSE; + char s[256], e[512]; + int n; + pid_t ppid; + + if(already_done) + return; + already_done = TRUE; + ppid = getppid(); + snprintf(s, sizeof(s), "/proc/%d/exe", ppid); + n = readlink(s, e, sizeof(e)); + if(n < 0) + return; + + e[MIN(n,sizeof(e)-1)] = '\0'; + + if(strstr(e,"gdb")) { + gaim_debug_info("dns", + "Debugger detected, performing useless query...\n"); + gethostbyname("x.x.x.x.x"); + } +#endif +} + +static void +gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug) +{ + dns_params_t dns_params; + const size_t zero = 0; + int rc; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res, *tmp; + char servname[20]; +#else + struct sockaddr_in sin; + const size_t addrlen = sizeof(sin); +#endif + +#ifdef HAVE_SIGNAL_H + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGTRAP, trap_gdb_bug); +#endif + + /* + * We resolve 1 host name for each iteration of this + * while loop. + * + * The top half of this reads in the hostname and port + * number from the socket with our parent. The bottom + * half of this resolves the IP (blocking) and sends + * the result back to our parent, when finished. + */ + while (1) { + const char ch = 'Y'; + fd_set fds; + struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; + FD_ZERO(&fds); + FD_SET(child_in, &fds); + rc = select(child_in + 1, &fds, NULL, NULL, &tv); + if (!rc) { + if (show_debug) + printf("dns[%d]: nobody needs me... =(\n", getpid()); + break; + } + rc = read(child_in, &dns_params, sizeof(dns_params_t)); + if (rc < 0) { + perror("read()"); + break; + } + if (rc == 0) { + if (show_debug) + printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid()); + _exit(0); + } + if (dns_params.hostname[0] == '\0') { + printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); + _exit(1); + } + /* Tell our parent that we read the data successfully */ + write(child_out, &ch, sizeof(ch)); + + /* We have the hostname and port, now resolve the IP */ + +#ifdef HAVE_GETADDRINFO + g_snprintf(servname, sizeof(servname), "%d", dns_params.port); + memset(&hints, 0, sizeof(hints)); + + /* This is only used to convert a service + * name to a port number. As we know we are + * passing a number already, we know this + * value will not be really used by the C + * library. + */ + hints.ai_socktype = SOCK_STREAM; + rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); + write(child_out, &rc, sizeof(rc)); + if (rc != 0) { + close(child_out); + if (show_debug) + printf("dns[%d] Error: getaddrinfo returned %d\n", + getpid(), rc); + dns_params.hostname[0] = '\0'; + continue; + } + tmp = res; + while (res) { + size_t ai_addrlen = res->ai_addrlen; + write(child_out, &ai_addrlen, sizeof(ai_addrlen)); + write(child_out, res->ai_addr, res->ai_addrlen); + res = res->ai_next; + } + freeaddrinfo(tmp); + write(child_out, &zero, sizeof(zero)); +#else + if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { + struct hostent *hp; + if (!(hp = gethostbyname(dns_params.hostname))) { + write(child_out, &h_errno, sizeof(int)); + close(child_out); + if (show_debug) + printf("DNS Error: %d\n", h_errno); + _exit(0); + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + + sin.sin_port = htons(dns_params.port); + write(child_out, &addrlen, sizeof(addrlen)); + write(child_out, &sin, addrlen); + write(child_out, &zero, sizeof(zero)); +#endif + dns_params.hostname[0] = '\0'; + } + + close(child_out); + close(child_in); + + _exit(0); +} + +static pending_dns_request_t * +gaim_dns_new_resolverthread(gboolean show_debug) +{ + pending_dns_request_t *req; + int child_out[2], child_in[2]; + + /* Create pipes for communicating with the child process */ + if (pipe(child_out) || pipe(child_in)) { + gaim_debug_error("dns", + "Could not create pipes: %s\n", strerror(errno)); + return NULL; + } + + req = g_new(pending_dns_request_t, 1); + + cope_with_gdb_brokenness(); + + /* Fork! */ + req->dns_pid = fork(); + + /* If we are the child process... */ + if (req->dns_pid == 0) { + /* We should not access the parent's side of the pipes, so close them */ + close(child_out[0]); + close(child_in[1]); + + gaim_dns_resolverthread(child_out[1], child_in[0], show_debug); + /* The thread calls _exit() rather than returning, so we never get here */ + } + + /* We should not access the child's side of the pipes, so close them */ + close(child_out[1]); + close(child_in[0]); + if (req->dns_pid == -1) { + gaim_debug_error("dns", + "Could not create child process for DNS: %s\n", + strerror(errno)); + g_free(req); + return NULL; + } + + req->fd_out = child_out[0]; + req->fd_in = child_in[1]; + number_of_dns_children++; + gaim_debug_info("dns", + "Created new DNS child %d, there are now %d children.\n", + req->dns_pid, number_of_dns_children); + + return req; +} +/* + * End the DNS resolver child process functions. + */ + +/* + * Begin the functions for dealing with the DNS child processes. + */ +static void +req_free(pending_dns_request_t *req) +{ + g_return_if_fail(req != NULL); + + close(req->fd_in); + close(req->fd_out); + + g_free(req->host); + g_free(req); + + number_of_dns_children--; +} + +static int +send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) +{ + char ch; + int rc; + pid_t pid; + + /* This waitpid might return the child's PID if it has recently + * exited, or it might return an error if it exited "long + * enough" ago that it has already been reaped; in either + * instance, we can't use it. */ + if ((pid = waitpid (req->dns_pid, NULL, WNOHANG)) > 0) { + gaim_debug_warning("dns", + "DNS child %d no longer exists\n", req->dns_pid); + return -1; + } else if (pid < 0) { + gaim_debug_warning("dns", + "Wait for DNS child %d failed: %s\n", + req->dns_pid, strerror(errno)); + return -1; + } + + /* Let's contact this lost child! */ + rc = write(req->fd_in, dns_params, sizeof(*dns_params)); + if (rc < 0) { + gaim_debug_error("dns", + "Unable to write to DNS child %d: %d\n", + req->dns_pid, strerror(errno)); + close(req->fd_in); + return -1; + } + + g_return_val_if_fail(rc == sizeof(*dns_params), -1); + + /* Did you hear me? (This avoids some race conditions) */ + rc = read(req->fd_out, &ch, sizeof(ch)); + if (rc != 1 || ch != 'Y') + { + gaim_debug_warning("dns", + "DNS child %d not responding. Killing it!\n", + req->dns_pid); + kill(req->dns_pid, SIGKILL); + return -1; + } + + gaim_debug_info("dns", + "Successfully sent DNS request to child %d\n", req->dns_pid); + + return 0; +} + +static void +host_resolved(gpointer data, gint source, GaimInputCondition cond); + +static void +release_dns_child(pending_dns_request_t *req) +{ + g_free(req->host); + req->host = NULL; + + if (queued_requests && !g_queue_is_empty(queued_requests)) { + queued_dns_request_t *r = g_queue_pop_head(queued_requests); + req->host = g_strdup(r->params.hostname); + req->port = r->params.port; + req->callback = r->callback; + req->data = r->data; + + gaim_debug_info("dns", + "Processing queued DNS query for '%s' with child %d\n", + req->host, req->dns_pid); + + if (send_dns_request_to_child(req, &(r->params)) != 0) { + req_free(req); + req = NULL; + + gaim_debug_warning("dns", + "Intent of process queued query of '%s' failed, " + "requeueing...\n", r->params.hostname); + g_queue_push_head(queued_requests, r); + } else { + req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); + g_free(r); + } + + } else { + req->host = NULL; + req->callback = NULL; + req->data = NULL; + free_dns_children = g_slist_append(free_dns_children, req); + } +} + +static void +host_resolved(gpointer data, gint source, GaimInputCondition cond) +{ + pending_dns_request_t *req = (pending_dns_request_t*)data; + int rc, err; + GSList *hosts = NULL; + struct sockaddr *addr = NULL; + size_t addrlen; + + gaim_debug_info("dns", "Got response for '%s'\n", req->host); + gaim_input_remove(req->inpa); + + rc = read(req->fd_out, &err, sizeof(err)); + if ((rc == 4) && (err != 0)) + { + char message[1024]; +#ifdef HAVE_GETADDRINFO + g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)", + gai_strerror(err), req->dns_pid); +#else + g_snprintf(message, sizeof(message), "DNS error: %d (pid=%d)", + err, req->dns_pid); +#endif + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + release_dns_child(req); + return; + } + if (rc > 0) + { + while (rc > 0) { + rc = read(req->fd_out, &addrlen, sizeof(addrlen)); + if (rc > 0 && addrlen > 0) { + addr = g_malloc(addrlen); + rc = read(req->fd_out, addr, addrlen); + hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); + hosts = g_slist_append(hosts, addr); + } else { + break; + } + } + } else if (rc == -1) { + char message[1024]; + g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + req_free(req); + return; + } else if (rc == 0) { + char message[1024]; + g_snprintf(message, sizeof(message), "EOF reading from DNS child"); + close(req->fd_out); + gaim_debug_error("dns", "%s\n", message); + req->callback(NULL, req->data, message); + req_free(req); + return; + } + +/* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ + + req->callback(hosts, req->data, NULL); + + release_dns_child(req); +} +/* + * End the functions for dealing with the DNS child processes. + */ + +int +gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data) +{ + pending_dns_request_t *req = NULL; + dns_params_t dns_params; + gchar *host_temp; + gboolean show_debug; + + show_debug = gaim_debug_is_enabled(); + + host_temp = g_strstrip(g_strdup(hostname)); + strncpy(dns_params.hostname, host_temp, sizeof(dns_params.hostname) - 1); + g_free(host_temp); + dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0'; + dns_params.port = port; + + /* + * If we have any children, attempt to have them perform the DNS + * query. If we're able to send the query to a child, then req + * will be set to the pending_dns_request_t. Otherwise, req will + * be NULL and we'll need to create a new DNS request child. + */ + while (free_dns_children != NULL) { + req = free_dns_children->data; + free_dns_children = g_slist_remove(free_dns_children, req); + + if (send_dns_request_to_child(req, &dns_params) == 0) + /* We found an acceptable child, yay */ + break; + + req_free(req); + req = NULL; + } + + /* We need to create a new DNS request child */ + if (req == NULL) { + if (number_of_dns_children >= MAX_DNS_CHILDREN) { + queued_dns_request_t *r = g_new(queued_dns_request_t, 1); + memcpy(&(r->params), &dns_params, sizeof(dns_params)); + r->callback = callback; + r->data = data; + if (!queued_requests) + queued_requests = g_queue_new(); + g_queue_push_tail(queued_requests, r); + + gaim_debug_info("dns", + "DNS query for '%s' queued\n", dns_params.hostname); + + return 0; + } + + req = gaim_dns_new_resolverthread(show_debug); + if (req == NULL) + { + gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n"); + return -1; + } + send_dns_request_to_child(req, &dns_params); + } + + req->host = g_strdup(hostname); + req->port = port; + req->callback = callback; + req->data = data; + req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); + + return 0; +} + +#elif defined _WIN32 /* end __unix__ || __APPLE__ */ + +typedef struct _dns_tdata { + char *hostname; + int port; + GaimProxyDnsConnectFunction callback; + gpointer data; + GSList *hosts; + char *errmsg; +} dns_tdata; + +static gboolean dns_main_thread_cb(gpointer data) { + dns_tdata *td = (dns_tdata*)data; + if (td->errmsg != NULL) { + gaim_debug_info("dns", "%s\n", td->errmsg); + } + td->callback(td->hosts, td->data, td->errmsg); + g_free(td->hostname); + g_free(td->errmsg); + g_free(td); + return FALSE; +} + +static gpointer dns_thread(gpointer data) { + +#ifdef HAVE_GETADDRINFO + int rc; + struct addrinfo hints, *res, *tmp; + char servname[20]; +#else + struct sockaddr_in sin; + struct hostent *hp; +#endif + dns_tdata *td = (dns_tdata*)data; + +#ifdef HAVE_GETADDRINFO + g_snprintf(servname, sizeof(servname), "%d", td->port); + memset(&hints,0,sizeof(hints)); + + /* This is only used to convert a service + * name to a port number. As we know we are + * passing a number already, we know this + * value will not be really used by the C + * library. + */ + hints.ai_socktype = SOCK_STREAM; + if ((rc = getaddrinfo(td->hostname, servname, &hints, &res)) == 0) { + tmp = res; + while(res) { + td->hosts = g_slist_append(td->hosts, + GSIZE_TO_POINTER(res->ai_addrlen)); + td->hosts = g_slist_append(td->hosts, + g_memdup(res->ai_addr, res->ai_addrlen)); + res = res->ai_next; + } + freeaddrinfo(tmp); + } else { + td->errmsg = g_strdup_printf("DNS getaddrinfo(\"%s\", \"%s\") error: %d", td->hostname, servname, rc); + } +#else + if ((hp = gethostbyname(td->hostname))) { + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(td->port); + + td->hosts = g_slist_append(td->hosts, + GSIZE_TO_POINTER(sizeof(sin))); + td->hosts = g_slist_append(td->hosts, + g_memdup(&sin, sizeof(sin))); + } else { + td->errmsg = g_strdup_printf("DNS gethostbyname(\"%s\") error: %d", td->hostname, h_errno); + } +#endif + /* back to main thread */ + g_idle_add(dns_main_thread_cb, td); + return 0; +} + +int +gaim_gethostbyname_async(const char *hostname, int port, + GaimProxyDnsConnectFunction callback, gpointer data) +{ + dns_tdata *td; + struct sockaddr_in sin; + GError* err = NULL; + + if(inet_aton(hostname, &sin.sin_addr)) { + GSList *hosts = NULL; + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); + hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); + callback(hosts, data, NULL); + return 0; + } + + gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname); + td = g_new0(dns_tdata, 1); + td->hostname = g_strdup(hostname); + td->port = port; + td->callback = callback; + td->data = data; + + if(!g_thread_create(dns_thread, td, FALSE, &err)) { + gaim_debug_error("dns", "DNS thread create failure: %s\n", err?err->message:""); + g_error_free(err); + g_free(td->hostname); + g_free(td); + return -1; + } + return 0; +} + +#else /* not __unix__ or __APPLE__ or _WIN32 */ + +typedef struct { + gpointer data; + size_t addrlen; + struct sockaddr *addr; + GaimProxyDnsConnectFunction callback; +} pending_dns_request_t; + +static gboolean host_resolved(gpointer data) +{ + pending_dns_request_t *req = (pending_dns_request_t*)data; + GSList *hosts = NULL; + hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen)); + hosts = g_slist_append(hosts, req->addr); + req->callback(hosts, req->data, NULL); + g_free(req); + return FALSE; +} + +int +gaim_gethostbyname_async(const char *hostname, int port, + GaimProxyDnsConnectFunction callback, gpointer data) +{ + struct sockaddr_in sin; + pending_dns_request_t *req; + + if (!inet_aton(hostname, &sin.sin_addr)) { + struct hostent *hp; + if(!(hp = gethostbyname(hostname))) { + gaim_debug_error("dns", + "gaim_gethostbyname(\"%s\", %d) failed: %d\n", + hostname, port, h_errno); + return -1; + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + req = g_new(pending_dns_request_t, 1); + req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin)); + req->addrlen = sizeof(sin); + req->data = data; + req->callback = callback; + gaim_timeout_add(10, host_resolved, req); + return 0; +} + +#endif /* not __unix__ or __APPLE__ or _WIN32 */ Property changes on: trunk/src/dnsquery.c ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: trunk/src/dnsquery.h =================================================================== --- trunk/src/dnsquery.h (rev 0) +++ trunk/src/dnsquery.h 2006-08-18 07:20:31 UTC (rev 16833) @@ -0,0 +1,67 @@ +/** + * @file dnsquery.h DNS query API + * @ingroup core + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GAIM_DNSQUERY_H_ +#define _GAIM_DNSQUERY_H_ + +#include <glib.h> +#include "eventloop.h" + +/** + * The "hosts" parameter is a linked list containing pairs of + * one size_t addrlen and one struct sockaddr *addr. + */ +typedef void (*GaimProxyDnsConnectFunction)(GSList *hosts, gpointer data, const char *error_message); + + +#include "account.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************/ +/** @name DNS query API */ +/**************************************************************************/ +/*@{*/ + +/** + * Do an async dns query + * + * @param hostname The hostname to resolve + * @param port A portnumber which is stored in the struct sockaddr + * @param callback Callback to call after resolving + * @param data Extra data for the callback function + * + * @return Zero indicates the connection is pending. Any other value indicates failure. + */ +int gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data); + +/*@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _GAIM_DNSQUERY_H_ */ Property changes on: trunk/src/dnsquery.h ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Modified: trunk/src/protocols/simple/simple.c =================================================================== --- trunk/src/protocols/simple/simple.c 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/protocols/simple/simple.c 2006-08-18 07:20:31 UTC (rev 16833) @@ -29,6 +29,7 @@ #include "accountopt.h" #include "blist.h" #include "conversation.h" +#include "dnsquery.h" #include "debug.h" #include "notify.h" #include "privacy.h" Modified: trunk/src/proxy.c =================================================================== --- trunk/src/proxy.c 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/proxy.c 2006-08-18 07:20:31 UTC (rev 16833) @@ -32,6 +32,7 @@ #include "internal.h" #include "cipher.h" #include "debug.h" +#include "dnsquery.h" #include "notify.h" #include "ntlm.h" #include "prefs.h" @@ -351,681 +352,7 @@ gaim_proxy_connect_info_destroy(connect_info); } -#if defined(__unix__) || defined(__APPLE__) - -/* - * This structure represents both a pending DNS request and - * a free child process. - */ -typedef struct { - char *host; - int port; - GaimProxyDnsConnectFunction callback; - gpointer data; - guint inpa; - int fd_in, fd_out; - pid_t dns_pid; -} pending_dns_request_t; - -static GSList *free_dns_children = NULL; -static GQueue *queued_requests = NULL; - -static int number_of_dns_children = 0; - -static const int MAX_DNS_CHILDREN = 2; - -typedef struct { - char hostname[512]; - int port; -} dns_params_t; - -typedef struct { - dns_params_t params; - GaimProxyDnsConnectFunction callback; - gpointer data; -} queued_dns_request_t; - -/* - * Begin the DNS resolver child process functions. - */ -#ifdef HAVE_SIGNAL_H static void -trap_gdb_bug() -{ - const char *message = - "Gaim's DNS child got a SIGTRAP signal.\n" - "This can be caused by trying to run gaim inside gdb.\n" - "There is a known gdb bug which prevents this. Supposedly gaim\n" - "should have detected you were using gdb and used an ugly hack,\n" - "check cope_with_gdb_brokenness() in proxy.c.\n\n" - "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n"; - fputs("\n* * *\n",stderr); - fputs(message,stderr); - fputs("* * *\n\n",stderr); - execlp("xmessage","xmessage","-center", message, NULL); - _exit(1); -} -#endif - -static void -cope_with_gdb_brokenness() -{ -#ifdef __linux__ - static gboolean already_done = FALSE; - char s[256], e[512]; - int n; - pid_t ppid; - - if(already_done) - return; - already_done = TRUE; - ppid = getppid(); - snprintf(s, sizeof(s), "/proc/%d/exe", ppid); - n = readlink(s, e, sizeof(e)); - if(n < 0) - return; - - e[MIN(n,sizeof(e)-1)] = '\0'; - - if(strstr(e,"gdb")) { - gaim_debug_info("dns", - "Debugger detected, performing useless query...\n"); - gethostbyname("x.x.x.x.x"); - } -#endif -} - -static void -gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug) -{ - dns_params_t dns_params; - const size_t zero = 0; - int rc; -#ifdef HAVE_GETADDRINFO - struct addrinfo hints, *res, *tmp; - char servname[20]; -#else - struct sockaddr_in sin; - const size_t addrlen = sizeof(sin); -#endif - -#ifdef HAVE_SIGNAL_H - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGTRAP, trap_gdb_bug); -#endif - - /* - * We resolve 1 host name for each iteration of this - * while loop. - * - * The top half of this reads in the hostname and port - * number from the socket with our parent. The bottom - * half of this resolves the IP (blocking) and sends - * the result back to our parent, when finished. - */ - while (1) { - const char ch = 'Y'; - fd_set fds; - struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; - FD_ZERO(&fds); - FD_SET(child_in, &fds); - rc = select(child_in + 1, &fds, NULL, NULL, &tv); - if (!rc) { - if (show_debug) - printf("dns[%d]: nobody needs me... =(\n", getpid()); - break; - } - rc = read(child_in, &dns_params, sizeof(dns_params_t)); - if (rc < 0) { - perror("read()"); - break; - } - if (rc == 0) { - if (show_debug) - printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid()); - _exit(0); - } - if (dns_params.hostname[0] == '\0') { - printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); - _exit(1); - } - /* Tell our parent that we read the data successfully */ - write(child_out, &ch, sizeof(ch)); - - /* We have the hostname and port, now resolve the IP */ - -#ifdef HAVE_GETADDRINFO - g_snprintf(servname, sizeof(servname), "%d", dns_params.port); - memset(&hints, 0, sizeof(hints)); - - /* This is only used to convert a service - * name to a port number. As we know we are - * passing a number already, we know this - * value will not be really used by the C - * library. - */ - hints.ai_socktype = SOCK_STREAM; - rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); - write(child_out, &rc, sizeof(rc)); - if (rc != 0) { - close(child_out); - if (show_debug) - printf("dns[%d] Error: getaddrinfo returned %d\n", - getpid(), rc); - dns_params.hostname[0] = '\0'; - continue; - } - tmp = res; - while (res) { - size_t ai_addrlen = res->ai_addrlen; - write(child_out, &ai_addrlen, sizeof(ai_addrlen)); - write(child_out, res->ai_addr, res->ai_addrlen); - res = res->ai_next; - } - freeaddrinfo(tmp); - write(child_out, &zero, sizeof(zero)); -#else - if (!inet_aton(dns_params.hostname, &sin.sin_addr)) { - struct hostent *hp; - if (!(hp = gethostbyname(dns_params.hostname))) { - write(child_out, &h_errno, sizeof(int)); - close(child_out); - if (show_debug) - printf("DNS Error: %d\n", h_errno); - _exit(0); - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - - sin.sin_port = htons(dns_params.port); - write(child_out, &addrlen, sizeof(addrlen)); - write(child_out, &sin, addrlen); - write(child_out, &zero, sizeof(zero)); -#endif - dns_params.hostname[0] = '\0'; - } - - close(child_out); - close(child_in); - - _exit(0); -} - -static pending_dns_request_t * -gaim_dns_new_resolverthread(gboolean show_debug) -{ - pending_dns_request_t *req; - int child_out[2], child_in[2]; - - /* Create pipes for communicating with the child process */ - if (pipe(child_out) || pipe(child_in)) { - gaim_debug_error("dns", - "Could not create pipes: %s\n", strerror(errno)); - return NULL; - } - - req = g_new(pending_dns_request_t, 1); - - cope_with_gdb_brokenness(); - - /* Fork! */ - req->dns_pid = fork(); - - /* If we are the child process... */ - if (req->dns_pid == 0) { - /* We should not access the parent's side of the pipes, so close them */ - close(child_out[0]); - close(child_in[1]); - - gaim_dns_resolverthread(child_out[1], child_in[0], show_debug); - /* The thread calls _exit() rather than returning, so we never get here */ - } - - /* We should not access the child's side of the pipes, so close them */ - close(child_out[1]); - close(child_in[0]); - if (req->dns_pid == -1) { - gaim_debug_error("dns", - "Could not create child process for DNS: %s\n", - strerror(errno)); - g_free(req); - return NULL; - } - - req->fd_out = child_out[0]; - req->fd_in = child_in[1]; - number_of_dns_children++; - gaim_debug_info("dns", - "Created new DNS child %d, there are now %d children.\n", - req->dns_pid, number_of_dns_children); - - return req; -} -/* - * End the DNS resolver child process functions. - */ - -/* - * Begin the functions for dealing with the DNS child processes. - */ -static void -req_free(pending_dns_request_t *req) -{ - g_return_if_fail(req != NULL); - - close(req->fd_in); - close(req->fd_out); - - g_free(req->host); - g_free(req); - - number_of_dns_children--; -} - -static int -send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) -{ - char ch; - int rc; - pid_t pid; - - /* This waitpid might return the child's PID if it has recently - * exited, or it might return an error if it exited "long - * enough" ago that it has already been reaped; in either - * instance, we can't use it. */ - if ((pid = waitpid (req->dns_pid, NULL, WNOHANG)) > 0) { - gaim_debug_warning("dns", - "DNS child %d no longer exists\n", req->dns_pid); - return -1; - } else if (pid < 0) { - gaim_debug_warning("dns", - "Wait for DNS child %d failed: %s\n", - req->dns_pid, strerror(errno)); - return -1; - } - - /* Let's contact this lost child! */ - rc = write(req->fd_in, dns_params, sizeof(*dns_params)); - if (rc < 0) { - gaim_debug_error("dns", - "Unable to write to DNS child %d: %d\n", - req->dns_pid, strerror(errno)); - close(req->fd_in); - return -1; - } - - g_return_val_if_fail(rc == sizeof(*dns_params), -1); - - /* Did you hear me? (This avoids some race conditions) */ - rc = read(req->fd_out, &ch, sizeof(ch)); - if (rc != 1 || ch != 'Y') - { - gaim_debug_warning("dns", - "DNS child %d not responding. Killing it!\n", - req->dns_pid); - kill(req->dns_pid, SIGKILL); - return -1; - } - - gaim_debug_info("dns", - "Successfully sent DNS request to child %d\n", req->dns_pid); - - return 0; -} - -static void -host_resolved(gpointer data, gint source, GaimInputCondition cond); - -static void -release_dns_child(pending_dns_request_t *req) -{ - g_free(req->host); - req->host = NULL; - - if (queued_requests && !g_queue_is_empty(queued_requests)) { - queued_dns_request_t *r = g_queue_pop_head(queued_requests); - req->host = g_strdup(r->params.hostname); - req->port = r->params.port; - req->callback = r->callback; - req->data = r->data; - - gaim_debug_info("dns", - "Processing queued DNS query for '%s' with child %d\n", - req->host, req->dns_pid); - - if (send_dns_request_to_child(req, &(r->params)) != 0) { - req_free(req); - req = NULL; - - gaim_debug_warning("dns", - "Intent of process queued query of '%s' failed, " - "requeueing...\n", r->params.hostname); - g_queue_push_head(queued_requests, r); - } else { - req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); - g_free(r); - } - - } else { - req->host = NULL; - req->callback = NULL; - req->data = NULL; - free_dns_children = g_slist_append(free_dns_children, req); - } -} - -static void -host_resolved(gpointer data, gint source, GaimInputCondition cond) -{ - pending_dns_request_t *req = (pending_dns_request_t*)data; - int rc, err; - GSList *hosts = NULL; - struct sockaddr *addr = NULL; - size_t addrlen; - - gaim_debug_info("dns", "Got response for '%s'\n", req->host); - gaim_input_remove(req->inpa); - - rc = read(req->fd_out, &err, sizeof(err)); - if ((rc == 4) && (err != 0)) - { - char message[1024]; -#ifdef HAVE_GETADDRINFO - g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)", - gai_strerror(err), req->dns_pid); -#else - g_snprintf(message, sizeof(message), "DNS error: %d (pid=%d)", - err, req->dns_pid); -#endif - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - release_dns_child(req); - return; - } - if (rc > 0) - { - while (rc > 0) { - rc = read(req->fd_out, &addrlen, sizeof(addrlen)); - if (rc > 0 && addrlen > 0) { - addr = g_malloc(addrlen); - rc = read(req->fd_out, addr, addrlen); - hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); - hosts = g_slist_append(hosts, addr); - } else { - break; - } - } - } else if (rc == -1) { - char message[1024]; - g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - req_free(req); - return; - } else if (rc == 0) { - char message[1024]; - g_snprintf(message, sizeof(message), "EOF reading from DNS child"); - close(req->fd_out); - gaim_debug_error("dns", "%s\n", message); - req->callback(NULL, req->data, message); - req_free(req); - return; - } - -/* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ - - req->callback(hosts, req->data, NULL); - - release_dns_child(req); -} -/* - * End the functions for dealing with the DNS child processes. - */ - -int -gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data) -{ - pending_dns_request_t *req = NULL; - dns_params_t dns_params; - gchar *host_temp; - gboolean show_debug; - - show_debug = gaim_debug_is_enabled(); - - host_temp = g_strstrip(g_strdup(hostname)); - strncpy(dns_params.hostname, host_temp, sizeof(dns_params.hostname) - 1); - g_free(host_temp); - dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0'; - dns_params.port = port; - - /* - * If we have any children, attempt to have them perform the DNS - * query. If we're able to send the query to a child, then req - * will be set to the pending_dns_request_t. Otherwise, req will - * be NULL and we'll need to create a new DNS request child. - */ - while (free_dns_children != NULL) { - req = free_dns_children->data; - free_dns_children = g_slist_remove(free_dns_children, req); - - if (send_dns_request_to_child(req, &dns_params) == 0) - /* We found an acceptable child, yay */ - break; - - req_free(req); - req = NULL; - } - - /* We need to create a new DNS request child */ - if (req == NULL) { - if (number_of_dns_children >= MAX_DNS_CHILDREN) { - queued_dns_request_t *r = g_new(queued_dns_request_t, 1); - memcpy(&(r->params), &dns_params, sizeof(dns_params)); - r->callback = callback; - r->data = data; - if (!queued_requests) - queued_requests = g_queue_new(); - g_queue_push_tail(queued_requests, r); - - gaim_debug_info("dns", - "DNS query for '%s' queued\n", dns_params.hostname); - - return 0; - } - - req = gaim_dns_new_resolverthread(show_debug); - if (req == NULL) - { - gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n"); - return -1; - } - send_dns_request_to_child(req, &dns_params); - } - - req->host = g_strdup(hostname); - req->port = port; - req->callback = callback; - req->data = data; - req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); - - return 0; -} - -#elif defined _WIN32 /* end __unix__ || __APPLE__ */ - -typedef struct _dns_tdata { - char *hostname; - int port; - GaimProxyDnsConnectFunction callback; - gpointer data; - GSList *hosts; - char *errmsg; -} dns_tdata; - -static gboolean dns_main_thread_cb(gpointer data) { - dns_tdata *td = (dns_tdata*)data; - if (td->errmsg != NULL) { - gaim_debug_info("dns", "%s\n", td->errmsg); - } - td->callback(td->hosts, td->data, td->errmsg); - g_free(td->hostname); - g_free(td->errmsg); - g_free(td); - return FALSE; -} - -static gpointer dns_thread(gpointer data) { - -#ifdef HAVE_GETADDRINFO - int rc; - struct addrinfo hints, *res, *tmp; - char servname[20]; -#else - struct sockaddr_in sin; - struct hostent *hp; -#endif - dns_tdata *td = (dns_tdata*)data; - -#ifdef HAVE_GETADDRINFO - g_snprintf(servname, sizeof(servname), "%d", td->port); - memset(&hints,0,sizeof(hints)); - - /* This is only used to convert a service - * name to a port number. As we know we are - * passing a number already, we know this - * value will not be really used by the C - * library. - */ - hints.ai_socktype = SOCK_STREAM; - if ((rc = getaddrinfo(td->hostname, servname, &hints, &res)) == 0) { - tmp = res; - while(res) { - td->hosts = g_slist_append(td->hosts, - GSIZE_TO_POINTER(res->ai_addrlen)); - td->hosts = g_slist_append(td->hosts, - g_memdup(res->ai_addr, res->ai_addrlen)); - res = res->ai_next; - } - freeaddrinfo(tmp); - } else { - td->errmsg = g_strdup_printf("DNS getaddrinfo(\"%s\", \"%s\") error: %d", td->hostname, servname, rc); - } -#else - if ((hp = gethostbyname(td->hostname))) { - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - sin.sin_port = htons(td->port); - - td->hosts = g_slist_append(td->hosts, - GSIZE_TO_POINTER(sizeof(sin))); - td->hosts = g_slist_append(td->hosts, - g_memdup(&sin, sizeof(sin))); - } else { - td->errmsg = g_strdup_printf("DNS gethostbyname(\"%s\") error: %d", td->hostname, h_errno); - } -#endif - /* back to main thread */ - g_idle_add(dns_main_thread_cb, td); - return 0; -} - -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) -{ - dns_tdata *td; - struct sockaddr_in sin; - GError* err = NULL; - - if(inet_aton(hostname, &sin.sin_addr)) { - GSList *hosts = NULL; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin))); - hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin))); - callback(hosts, data, NULL); - return 0; - } - - gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname); - td = g_new0(dns_tdata, 1); - td->hostname = g_strdup(hostname); - td->port = port; - td->callback = callback; - td->data = data; - - if(!g_thread_create(dns_thread, td, FALSE, &err)) { - gaim_debug_error("dns", "DNS thread create failure: %s\n", err?err->message:""); - g_error_free(err); - g_free(td->hostname); - g_free(td); - return -1; - } - return 0; -} - -#else /* not __unix__ or __APPLE__ or _WIN32 */ - -typedef struct { - gpointer data; - size_t addrlen; - struct sockaddr *addr; - GaimProxyDnsConnectFunction callback; -} pending_dns_request_t; - -static gboolean host_resolved(gpointer data) -{ - pending_dns_request_t *req = (pending_dns_request_t*)data; - GSList *hosts = NULL; - hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen)); - hosts = g_slist_append(hosts, req->addr); - req->callback(hosts, req->data, NULL); - g_free(req); - return FALSE; -} - -int -gaim_gethostbyname_async(const char *hostname, int port, - GaimProxyDnsConnectFunction callback, gpointer data) -{ - struct sockaddr_in sin; - pending_dns_request_t *req; - - if (!inet_aton(hostname, &sin.sin_addr)) { - struct hostent *hp; - if(!(hp = gethostbyname(hostname))) { - gaim_debug_error("dns", - "gaim_gethostbyname(\"%s\", %d) failed: %d\n", - hostname, port, h_errno); - return -1; - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - req = g_new(pending_dns_request_t, 1); - req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin)); - req->addrlen = sizeof(sin); - req->data = data; - req->callback = callback; - gaim_timeout_add(10, host_resolved, req); - return 0; -} - -#endif /* not __unix__ or __APPLE__ or _WIN32 */ - -static void no_one_calls(gpointer data, gint source, GaimInputCondition cond) { GaimProxyConnectInfo *connect_info = data; Modified: trunk/src/proxy.h =================================================================== --- trunk/src/proxy.h 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/proxy.h 2006-08-18 07:20:31 UTC (rev 16833) @@ -60,13 +60,7 @@ typedef void (*GaimProxyConnectFunction)(gpointer data, gint source, const gchar *error_message); -/** - * The "hosts" parameter is a linked list containing pairs of - * one size_t addrlen and one struct sockaddr *addr. - */ -typedef void (*GaimProxyDnsConnectFunction)(GSList *hosts, gpointer data, const char *error_message); - #include "account.h" #ifdef __cplusplus @@ -278,18 +272,6 @@ */ void gaim_proxy_connect_cancel(GaimProxyConnectInfo *connect_info); -/** - * Do an async dns query - * - * @param hostname The hostname to resolve - * @param port A portnumber which is stored in the struct sockaddr - * @param callback Callback to call after resolving - * @param data Extra data for the callback function - * - * @return Zero indicates the connection is pending. Any other value indicates failure. - */ -int gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data); - /*@}*/ #ifdef __cplusplus Modified: trunk/src/stun.c =================================================================== --- trunk/src/stun.c 2006-08-18 06:40:16 UTC (rev 16832) +++ trunk/src/stun.c 2006-08-18 07:20:31 UTC (rev 16833) @@ -40,6 +40,7 @@ #include "debug.h" #include "account.h" +#include "dnsquery.h" #include "dnssrv.h" #include "network.h" #include "proxy.h" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 06:40:22
|
Revision: 16832 Author: thekingant Date: 2006-08-17 23:40:16 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16832&view=rev Log Message: ----------- Backport SVN revision 16818 and parts of 16827 from HEAD to v2_0_0 Original commit messages are below. datallah, you'll have to check if I missed anything from 16827... it was kinda hard to follow, and I think a lot of the changes were to blist efficiency code which isn't in v2_0_0. 16818: Remove a g_main_iteration, replace with an idle handler. Fixes the thread freeze on expanding contacts 16827: A couple of leak fixes, some avoidance of unnecessary memory allocation/freeing and some cleanup. There are a lot fewer changes if you ignore space changes. ViewCVS Links: ------------- http://svn.sourceforge.net/gaim/?rev=16818&view=rev Modified Paths: -------------- branches/v2_0_0/src/gtkblist.c Modified: branches/v2_0_0/src/gtkblist.c =================================================================== --- branches/v2_0_0/src/gtkblist.c 2006-08-18 06:18:38 UTC (rev 16831) +++ branches/v2_0_0/src/gtkblist.c 2006-08-18 06:40:16 UTC (rev 16832) @@ -846,6 +846,25 @@ } } +struct _expand { + GtkTreeView *treeview; + GtkTreePath *path; + GaimBlistNode *node; +}; + +static gboolean +scroll_to_expanded_cell(gpointer data) +{ + struct _expand *ex = data; + gtk_tree_view_scroll_to_cell(ex->treeview, ex->path, NULL, FALSE, 0, 0); + gaim_gtk_blist_update(NULL, ex->node); + + gtk_tree_path_free(ex->path); + g_free(ex); + + return FALSE; +} + static void gaim_gtk_blist_expand_contact_cb(GtkWidget *w, GaimBlistNode *node) { @@ -854,6 +873,8 @@ GaimBlistNode *bnode; GtkTreePath *path; + struct _expand *ex = g_new0(struct _expand, 1); + if(!GAIM_BLIST_NODE_IS_CONTACT(node)) return; @@ -870,14 +891,12 @@ gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtkblist->treemodel), &iter, &parent, gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtkblist->treemodel), &parent) -1); path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter); + /* Let the treeview draw so it knows where to scroll */ - while (gtk_events_pending()) - gtk_main_iteration(); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(gtkblist->treeview), path, NULL, FALSE, 0, 0); - - - gaim_gtk_blist_update(NULL, node); - gtk_tree_path_free(path); + ex->treeview = GTK_TREE_VIEW(gtkblist->treeview); + ex->path = path; + ex->node = node; + g_idle_add(scroll_to_expanded_cell, ex); } static void @@ -1636,7 +1655,7 @@ buddy->alias); } - str = g_string_append(str, "\r\n"); + g_string_append(str, "\r\n"); gtk_selection_data_set(data, gdk_atom_intern("application/x-im-contact", FALSE), @@ -2439,7 +2458,7 @@ { N_("/Buddies/Add C_hat..."), NULL, gaim_gtk_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD }, { N_("/Buddies/Add _Group..."), NULL, gaim_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD }, { "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL }, - { N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, + { N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, /* Accounts menu */ { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, @@ -3242,7 +3261,7 @@ } if(tooltip_text->len > 0) { /* get rid of the last newline */ - tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len -1); + g_string_truncate(tooltip_text, tooltip_text->len -1); img = gtk_image_new_from_stock(GAIM_STOCK_PENDING, GTK_ICON_SIZE_MENU); gtkblist->menutrayicon = gtk_event_box_new(); @@ -3715,6 +3734,8 @@ G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel)); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(gtkblist->treeview), TRUE); + gtk_widget_show(gtkblist->treeview); gtk_widget_set_name(gtkblist->treeview, "gaim_gtkblist_treeview"); @@ -3800,9 +3821,9 @@ gtkblist->statusbox = gtk_gaim_status_box_new(); gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0); gtk_widget_set_name(gtkblist->statusbox, "gaim_gtkblist_statusbox"); - gtk_gaim_status_box_set_buddy_icon(gtkblist->statusbox, gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon")); + gtk_gaim_status_box_set_buddy_icon(GTK_GAIM_STATUS_BOX(gtkblist->statusbox), gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon")); gtk_widget_show(gtkblist->statusbox); - + /* set the Show Offline Buddies option. must be done * after the treeview or faceprint gets mad. -Robot101 */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 06:18:50
|
Revision: 16831 Author: thekingant Date: 2006-08-17 23:18:38 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16831&view=rev Log Message: ----------- Backport SVN revisions 16815-16830 from HEAD to v2_0_0, excluding 16818 and 16827 (they were conflicting--I'll get to them in a minute). Original commit messages: 16815: If g_open isn't a macro, we need to specify the mode variable 16816: I will apologize in advance for this ugliness - it is necessary because we have a "connect" macro to cause the wgaim_connect() wrapper function to be used. 16817: nosnilmot pointed out that I'm an idiot and this is a far less ugly way to achieve the same goal. (I swear I tried it first, but must have not actually saved the file when I tested it). 16819: Patch to eggtrayicon by Dan Winship makes icon transparent 16820: Fix CID 250 (also change the behavior to be slightly more sane) and 213 (which wouldn't happen unless the sasl library returned some weird values) 16821: Patch #1523103 ("Improved markup processing"): "This patch tries to handle all the html-entities (including stuff like ® and &#xx;) in gaim_markup_strip_html and gaim_unescape_html. This also allows fixing the issue with libxml2 where & was being converted to &." 16822: Patch #1541742 ("Add boolean property \"iconsel\" for Statusbox"): "This adds a boolean property "iconsel" for statusbox. Setting the property to TRUE shows the icon-selector, setting it to FALSE removes it. It would allow plugins like mystatusbox to better control the statusboxes, especially the per-account ones." 16823: Patch #1541744 ("Memleak"): "This plugs a possible memleak." The memleak would happen if you switch from an account with account-options to an account with none. 16824: This is better. 16825: deryni noticed a missing ')' (it turns out I had SASL disabled) 16826: Fix asserts at startup. 16828: Get rid of an assertion failure when the selected icon is not a valid image 16829: Just rename connect to connectfunc. This is what it was like before my changes. Now I know why! 16830: Patch from Henning Nor?\195?\169n to not show ICQ users as "pending" when they are away without a message Modified Paths: -------------- branches/v2_0_0/COPYRIGHT branches/v2_0_0/ChangeLog branches/v2_0_0/plugins/docklet/eggtrayicon.c branches/v2_0_0/src/gtkaccount.c branches/v2_0_0/src/gtkstatusbox.c branches/v2_0_0/src/protocols/jabber/auth.c branches/v2_0_0/src/protocols/oscar/oscar.c branches/v2_0_0/src/protocols/silc/util.c branches/v2_0_0/src/sslconn.c branches/v2_0_0/src/sslconn.h branches/v2_0_0/src/util.c branches/v2_0_0/src/xmlnode.c Modified: branches/v2_0_0/COPYRIGHT =================================================================== --- branches/v2_0_0/COPYRIGHT 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/COPYRIGHT 2006-08-18 06:18:38 UTC (rev 16831) @@ -316,6 +316,7 @@ Dan Willemsen Jason Willis Matt Wilson +Dan Winship Scott Wolchok Pui Lam Wong Justin Wood Modified: branches/v2_0_0/ChangeLog =================================================================== --- branches/v2_0_0/ChangeLog 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/ChangeLog 2006-08-18 06:18:38 UTC (rev 16831) @@ -99,6 +99,7 @@ removed. * 'Highlight when nick said' option added to Message Notification plugin. + * The system tray icon is now transparent (Dan Winship) MSN Features: * Custom smiley receiving support (Irving Cordova & Francesco Fracassi) Modified: branches/v2_0_0/plugins/docklet/eggtrayicon.c =================================================================== --- branches/v2_0_0/plugins/docklet/eggtrayicon.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/plugins/docklet/eggtrayicon.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -54,6 +54,9 @@ static void egg_tray_icon_realize (GtkWidget *widget); static void egg_tray_icon_unrealize (GtkWidget *widget); +static void egg_tray_icon_add (GtkContainer *container, + GtkWidget *widget); + static void egg_tray_icon_update_manager_window (EggTrayIcon *icon, gboolean dock_if_realized); static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon); @@ -109,6 +112,7 @@ { GObjectClass *gobject_class = (GObjectClass *)klass; GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; + GtkContainerClass *container_class = (GtkContainerClass *)klass; parent_class = g_type_class_peek_parent (klass); @@ -117,6 +121,8 @@ widget_class->realize = egg_tray_icon_realize; widget_class->unrealize = egg_tray_icon_unrealize; + container_class->add = egg_tray_icon_add; + g_object_class_install_property (gobject_class, PROP_ORIENTATION, g_param_spec_enum ("orientation", @@ -374,7 +380,37 @@ egg_tray_icon_update_manager_window (icon, TRUE); } +static gboolean +transparent_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) +{ + gdk_window_clear_area (widget->window, event->area.x, event->area.y, + event->area.width, event->area.height); + return FALSE; +} + static void +make_transparent_again (GtkWidget *widget, GtkStyle *previous_style, + gpointer user_data) +{ + gdk_window_set_back_pixmap(widget->window, NULL, TRUE); +} + +static void +make_transparent (GtkWidget *widget, gpointer user_data) +{ + if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget)) + return; + + gtk_widget_set_app_paintable (widget, TRUE); + gtk_widget_set_double_buffered (widget, FALSE); + gdk_window_set_back_pixmap (widget->window, NULL, TRUE); + g_signal_connect (widget, "expose_event", + G_CALLBACK (transparent_expose_event), NULL); + g_signal_connect_after (widget, "style_set", + G_CALLBACK (make_transparent_again), NULL); +} + +static void egg_tray_icon_realize (GtkWidget *widget) { EggTrayIcon *icon = EGG_TRAY_ICON (widget); @@ -386,6 +422,8 @@ if (GTK_WIDGET_CLASS (parent_class)->realize) GTK_WIDGET_CLASS (parent_class)->realize (widget); + make_transparent (widget, NULL); + #if GTK_CHECK_VERSION(2,1,0) screen = gdk_screen_get_number (gtk_widget_get_screen (widget)); xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); @@ -425,6 +463,14 @@ egg_tray_icon_manager_filter, icon); } +static void +egg_tray_icon_add (GtkContainer *container, GtkWidget *widget) +{ + g_signal_connect (widget, "realize", + G_CALLBACK (make_transparent), NULL); + GTK_CONTAINER_CLASS (parent_class)->add (container, widget); +} + #if GTK_CHECK_VERSION(2,1,0) EggTrayIcon * egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) Modified: branches/v2_0_0/src/gtkaccount.c =================================================================== --- branches/v2_0_0/src/gtkaccount.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/gtkaccount.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -646,6 +646,11 @@ dialog->protocol_frame = NULL; } + if (dialog->protocol_opt_entries != NULL) { + g_list_free(dialog->protocol_opt_entries); + dialog->protocol_opt_entries = NULL; + } + if (dialog->prpl_info == NULL || dialog->prpl_info->protocol_options == NULL) { @@ -669,11 +674,6 @@ gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); - if (dialog->protocol_opt_entries != NULL) { - g_list_free(dialog->protocol_opt_entries); - dialog->protocol_opt_entries = NULL; - } - for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next) { option = (GaimAccountOption *)l->data; Modified: branches/v2_0_0/src/gtkstatusbox.c =================================================================== --- branches/v2_0_0/src/gtkstatusbox.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/gtkstatusbox.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -115,7 +115,8 @@ enum { PROP_0, - PROP_ACCOUNT + PROP_ACCOUNT, + PROP_ICON_SEL, }; GtkComboBoxClass *parent_class = NULL; @@ -163,6 +164,9 @@ case PROP_ACCOUNT: g_value_set_pointer(value, statusbox->account); break; + case PROP_ICON_SEL: + g_value_set_boolean(value, statusbox->icon_box != NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, psec); break; @@ -253,6 +257,9 @@ static void setup_icon_box(GtkGaimStatusBox *status_box) { + if (status_box->icon_box != NULL) + return; + if (status_box->account && !gaim_account_get_ui_bool(status_box->account, GAIM_GTK_UI, "use-global-buddyicon", TRUE)) { @@ -280,12 +287,54 @@ } static void +destroy_icon_box(GtkGaimStatusBox *statusbox) +{ + if (statusbox->icon_box == NULL) + return; + + gtk_widget_destroy(statusbox->icon_box); + gdk_cursor_unref(statusbox->hand_cursor); + gdk_cursor_unref(statusbox->arrow_cursor); + + g_object_unref(G_OBJECT(statusbox->buddy_icon)); + g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); + + if (statusbox->buddy_icon_sel) + gtk_widget_destroy(statusbox->buddy_icon_sel); + + g_free(statusbox->buddy_icon_path); + + statusbox->icon_box = NULL; + statusbox->buddy_icon_path = NULL; + statusbox->buddy_icon = NULL; + statusbox->buddy_icon_hover = NULL; + statusbox->hand_cursor = NULL; + statusbox->arrow_cursor = NULL; +} + +static void gtk_gaim_status_box_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); switch (param_id) { + case PROP_ICON_SEL: + if (g_value_get_boolean(value)) { + if (statusbox->account) { + GaimPlugin *plug = gaim_plugins_find_with_id(gaim_account_get_protocol_id(statusbox->account)); + if (plug) { + GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); + if (prplinfo && prplinfo->icon_spec.format != NULL) + setup_icon_box(statusbox); + } + } else { + setup_icon_box(statusbox); + } + } else { + destroy_icon_box(statusbox); + } + break; case PROP_ACCOUNT: statusbox->account = g_value_get_pointer(value); @@ -296,16 +345,9 @@ } if (statusbox->account) { - GaimPlugin *plug = gaim_plugins_find_with_id(gaim_account_get_protocol_id(statusbox->account)); - GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); - if (prplinfo && prplinfo->icon_spec.format != NULL) { - setup_icon_box(statusbox); - } statusbox->status_changed_signal = gaim_signal_connect(gaim_accounts_get_handle(), "account-status-changed", statusbox, GAIM_CALLBACK(account_status_changed_cb), statusbox); - } else { - setup_icon_box(statusbox); } gtk_gaim_status_box_regenerate(statusbox); @@ -365,6 +407,7 @@ combo_box_forall = container_class->forall; container_class->forall = gtk_gaim_status_box_forall; + container_class->remove = NULL; object_class = (GObjectClass *)klass; @@ -381,6 +424,15 @@ G_PARAM_READWRITE ) ); + g_object_class_install_property(object_class, + PROP_ICON_SEL, + g_param_spec_boolean("iconsel", + "Icon Selector", + "Whether the icon selector should be displayed or not.", + FALSE, + G_PARAM_READWRITE + ) + ); } /** @@ -1001,6 +1053,7 @@ gaim_account_set_buddy_icon(box->account, icon); g_free(icon); gaim_account_set_ui_bool(box->account, GAIM_GTK_UI, "use-global-buddyicon", FALSE); + gaim_account_set_ui_string(box->account, GAIM_GTK_UI, "non-global-buddyicon", icon); } } } else { @@ -1218,17 +1271,22 @@ if (status_box->icon_size != icon_alc.height) { + if (status_box->buddy_icon_hover) + g_object_unref(status_box->buddy_icon_hover); if ((status_box->buddy_icon_path != NULL) && (*status_box->buddy_icon_path != '\0')) { scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, icon_alc.height, icon_alc.width, FALSE, NULL); - g_object_unref(status_box->buddy_icon_hover); - status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); - do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); - g_object_unref(status_box->buddy_icon); - status_box->buddy_icon = scaled; - gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); + if (scaled != NULL) + { + status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); + if (status_box->buddy_icon) + g_object_unref(status_box->buddy_icon); + status_box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); + } } status_box->icon_size = icon_alc.height; } @@ -1247,7 +1305,8 @@ GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->vbox, event); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->toggle_button, event); - gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); + if (status_box->icon_box) + gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); return FALSE; } @@ -1274,13 +1333,15 @@ GtkWidget * gtk_gaim_status_box_new() { - return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", NULL, NULL); + return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", NULL, + "iconsel", TRUE, NULL); } GtkWidget * gtk_gaim_status_box_new_with_account(GaimAccount *account) { - return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, NULL); + return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, + "iconsel", TRUE, NULL); } /** @@ -1384,14 +1445,18 @@ { if (box->buddy_icon != NULL) g_object_unref(box->buddy_icon); - scaled = gdk_pixbuf_new_from_file_at_scale(filename, - box->icon_size, box->icon_size, FALSE, NULL); - if (scaled != NULL) - { - box->buddy_icon_hover = gdk_pixbuf_copy(scaled); - do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); - box->buddy_icon = scaled; - gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon); + + /* This will get called before the box is shown and will not have a size */ + if (box->icon_size > 0) { + scaled = gdk_pixbuf_new_from_file_at_scale(filename, + box->icon_size, box->icon_size, FALSE, NULL); + if (scaled != NULL) + { + box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); + box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon); + } } } Modified: branches/v2_0_0/src/protocols/jabber/auth.c =================================================================== --- branches/v2_0_0/src/protocols/jabber/auth.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/protocols/jabber/auth.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -181,9 +181,9 @@ static void jabber_auth_start_cyrus(JabberStream *js) { - const char *clientout, *mech; + const char *clientout = NULL, *mech = NULL; char *enc_out; - unsigned coutlen; + unsigned coutlen = 0; xmlnode *auth; sasl_security_properties_t secprops; gboolean again; @@ -256,21 +256,29 @@ /* For everything else, fail the mechanism and try again */ default: gaim_debug_info("sasl", "sasl_state is %d, failing the mech and trying again\n", js->sasl_state); - if (strlen(mech)>0) { + + /* + * DAA: is this right? + * The manpage says that "mech" will contain the chosen mechanism on success. + * Presumably, if we get here that isn't the case and we shouldn't try again? + * I suspect that this never happens. + */ + if (mech && strlen(mech) > 0) { char *pos; - pos = strstr(js->sasl_mechs->str,mech); - g_assert(pos!=NULL); - g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str,strlen(mech)); + if ((pos = strstr(js->sasl_mechs->str, mech))) { + g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(mech)); + } + again = TRUE; } + sasl_dispose(&js->sasl); - again=TRUE; } } while (again); if (js->sasl_state == SASL_CONTINUE || js->sasl_state == SASL_OK) { auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, "urn:ietf:params:xml:ns:xmpp-sasl"); - xmlnode_set_attrib(auth,"mechanism", mech); + xmlnode_set_attrib(auth, "mechanism", mech); if (clientout) { if (coutlen == 0) { xmlnode_insert_data(auth, "=", -1); @@ -332,7 +340,7 @@ char *mech_name = xmlnode_get_data(mechnode); #ifdef HAVE_CYRUS_SASL g_string_append(js->sasl_mechs, mech_name); - g_string_append_c(js->sasl_mechs,' '); + g_string_append_c(js->sasl_mechs, ' '); #else if(mech_name && !strcmp(mech_name, "DIGEST-MD5")) digest_md5 = TRUE; Modified: branches/v2_0_0/src/protocols/oscar/oscar.c =================================================================== --- branches/v2_0_0/src/protocols/oscar/oscar.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/protocols/oscar/oscar.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -2885,6 +2885,9 @@ gaim_status_set_attr_string(status, "message", message); g_free(message); } + else + /* Set an empty message so that we know not to show "pending" */ + gaim_status_set_attr_string(status, "message", message); gaim_blist_update_buddy_status(b, status); } Modified: branches/v2_0_0/src/protocols/silc/util.c =================================================================== --- branches/v2_0_0/src/protocols/silc/util.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/protocols/silc/util.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -234,7 +234,7 @@ } #endif - if ((fd = g_open(file_private_key, O_RDONLY)) != -1) { + if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { if ((fstat(fd, &st)) == -1) { gaim_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", file_private_key, strerror(errno)); @@ -254,7 +254,7 @@ return FALSE; } - if ((fd = g_open(file_private_key, O_RDONLY)) != -1) { + if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { if ((fstat(fd, &st)) == -1) { gaim_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", file_private_key, strerror(errno)); Modified: branches/v2_0_0/src/sslconn.c =================================================================== --- branches/v2_0_0/src/sslconn.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/sslconn.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -46,7 +46,7 @@ ops = gaim_ssl_get_ops(); if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) || - (ops->connect == NULL) || (ops->close == NULL) || + (ops->connectfunc == NULL) || (ops->close == NULL) || (ops->read == NULL) || (ops->write == NULL)) { return FALSE; @@ -87,7 +87,7 @@ gsc->fd = source; ops = gaim_ssl_get_ops(); - ops->connect(gsc); + ops->connectfunc(gsc); } GaimSslConnection * @@ -177,7 +177,7 @@ gsc->fd = fd; ops = gaim_ssl_get_ops(); - ops->connect(gsc); + ops->connectfunc(gsc); return (GaimSslConnection *)gsc; } Modified: branches/v2_0_0/src/sslconn.h =================================================================== --- branches/v2_0_0/src/sslconn.h 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/sslconn.h 2006-08-18 06:18:38 UTC (rev 16831) @@ -68,7 +68,7 @@ { gboolean (*init)(void); void (*uninit)(void); - void (*connect)(GaimSslConnection *gsc); + void (*connectfunc)(GaimSslConnection *gsc); void (*close)(GaimSslConnection *gsc); size_t (*read)(GaimSslConnection *gsc, void *data, size_t len); size_t (*write)(GaimSslConnection *gsc, const void *data, size_t len); Modified: branches/v2_0_0/src/util.c =================================================================== --- branches/v2_0_0/src/util.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/util.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -854,6 +854,55 @@ /************************************************************************** * Markup Functions **************************************************************************/ + +/* Returns a NULL-terminated string after unescaping an entity + * (eg. &, < & etc.) starting at s. Returns NULL on failure.*/ +static const char * +detect_entity(const char *text, int *length) +{ + const char *pln; + int len, pound; + + if (!text || *text != '&') + return NULL; + +#define IS_ENTITY(s) (!g_ascii_strncasecmp(text, s, (len = sizeof(s) - 1))) + + if(IS_ENTITY("&")) + pln = "&"; + else if(IS_ENTITY("<")) + pln = "<"; + else if(IS_ENTITY(">")) + pln = ">"; + else if(IS_ENTITY(" ")) + pln = " "; + else if(IS_ENTITY("©")) + pln = "\302\251"; /* or use g_unichar_to_utf8(0xa9); */ + else if(IS_ENTITY(""")) + pln = "\""; + else if(IS_ENTITY("®")) + pln = "\302\256"; /* or use g_unichar_to_utf8(0xae); */ + else if(IS_ENTITY("'")) + pln = "\'"; + else if(*(text+1) == '#' && (sscanf(text, "&#%u;", £) == 1) && + pound != 0 && *(text+3+(gint)log10(pound)) == ';') { + static char buf[7]; + int buflen = g_unichar_to_utf8((gunichar)pound, buf); + buf[buflen] = '\0'; + pln = buf; + + len = 2; + while(isdigit((gint) text[len])) len++; + if(text[len] == ';') len++; + } + else + return NULL; + + if (length) + *length = len; + return pln; +} + gboolean gaim_markup_find_tag(const char *needle, const char *haystack, const char **start, const char **end, GData **attributes) @@ -1443,44 +1492,10 @@ } } else if(*c == '&') { char buf[7]; - char *pln; - int len = 1; - guint pound; - if(!g_ascii_strncasecmp(c, "&", 5)) { - pln = "&"; - len = 5; - } else if(!g_ascii_strncasecmp(c, "<", 4)) { - pln = "<"; - len = 4; - } else if(!g_ascii_strncasecmp(c, ">", 4)) { - pln = ">"; - len = 4; - } else if(!g_ascii_strncasecmp(c, " ", 6)) { - pln = " "; - len = 6; - } else if(!g_ascii_strncasecmp(c, "©", 6)) { - pln = "©"; - len = 6; - } else if(!g_ascii_strncasecmp(c, """, 6)) { - pln = "\""; - len = 6; - } else if(!g_ascii_strncasecmp(c, "®", 5)) { - pln = "®"; - len = 5; - } else if(!g_ascii_strncasecmp(c, "'", 6)) { - pln = "\'"; - len = 6; - } else if(*(c+1) == '#' && (sscanf(c, "&#%u;", £) == 1) && - pound != 0 && *(c+3+(gint)log10(pound)) == ';') { - int buflen = g_unichar_to_utf8((gunichar)pound, buf); - buf[buflen] = '\0'; - pln = buf; + const char *pln; + int len; - - len = 2; - while(isdigit((gint) c [len])) len++; - if(c [len] == ';') len++; - } else { + if ((pln = detect_entity(c, &len)) == NULL) { len = 1; g_snprintf(buf, sizeof(buf), "%c", *c); pln = buf; @@ -1522,11 +1537,11 @@ char * gaim_markup_strip_html(const char *str) { - int i, j, k; + int i, j, k, entlen; gboolean visible = TRUE; gboolean closing_td_p = FALSE; gchar *str2; - const gchar *cdata_close_tag = NULL; + const gchar *cdata_close_tag = NULL, *ent; gchar *href = NULL; int href_st = 0; @@ -1685,44 +1700,14 @@ visible = TRUE; } - /* XXX: This sucks. We need to be un-escaping all entities, which - * includes these, as well as the &#num; ones */ - - if (str2[i] == '&' && strncasecmp(str2 + i, """, 6) == 0) + if (str2[i] == '&' && (ent = detect_entity(str2 + i, &entlen)) != NULL) { - str2[j++] = '\"'; - i = i + 5; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, "&", 5) == 0) - { - str2[j++] = '&'; - i = i + 4; + while (*ent) + str2[j++] = *ent++; + i += entlen - 1; continue; } - if (str2[i] == '&' && strncasecmp(str2 + i, "<", 4) == 0) - { - str2[j++] = '<'; - i = i + 3; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, ">", 4) == 0) - { - str2[j++] = '>'; - i = i + 3; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, "'", 6) == 0) - { - str2[j++] = '\''; - i = i + 5; - continue; - } - if (visible) str2[j++] = g_ascii_isspace(str2[i])? ' ': str2[i]; } @@ -2026,41 +2011,28 @@ char * gaim_unescape_html(const char *html) { - const char *c; - GString *ret; + if (html != NULL) { + const char *c = html; + GString *ret = g_string_new(""); + while (*c) { + int len; + const char *ent; - if (html == NULL) - return NULL; - - c = html; - ret = g_string_new(""); - while (*c) { - if (!strncmp(c, "&", 5)) { - ret = g_string_append_c(ret, '&'); - c += 5; - } else if (!strncmp(c, "<", 4)) { - ret = g_string_append_c(ret, '<'); - c += 4; - } else if (!strncmp(c, ">", 4)) { - ret = g_string_append_c(ret, '>'); - c += 4; - } else if (!strncmp(c, """, 6)) { - ret = g_string_append_c(ret, '"'); - c += 6; - } else if (!strncmp(c, "'", 6)) { - ret = g_string_append_c(ret, '\''); - c += 6; - } else if (!strncmp(c, "<br>", 4)) { - ret = g_string_append_c(ret, '\n'); - c += 4; - } else { - ret = g_string_append_c(ret, *c); - c++; + if ((ent = detect_entity(c, &len)) != NULL) { + ret = g_string_append(ret, ent); + c += len; + } else if (!strncmp(c, "<br>", 4)) { + ret = g_string_append_c(ret, '\n'); + c += 4; + } else { + ret = g_string_append_c(ret, *c); + c++; + } } + return g_string_free(ret, FALSE); } - return g_string_free(ret, FALSE); - + return NULL; } char * @@ -3996,4 +3968,3 @@ return buf; } - Modified: branches/v2_0_0/src/xmlnode.c =================================================================== --- branches/v2_0_0/src/xmlnode.c 2006-08-18 05:59:47 UTC (rev 16830) +++ branches/v2_0_0/src/xmlnode.c 2006-08-18 06:18:38 UTC (rev 16831) @@ -35,6 +35,7 @@ #include <string.h> #include <glib.h> +#include "util.h" #include "xmlnode.h" #ifdef _WIN32 @@ -406,6 +407,11 @@ char *attrib = g_malloc(attrib_len + 1); memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; +#ifdef HAVE_LIBXML + char *txt = attrib; + attrib = gaim_unescape_html(txt); + g_free(txt); +#endif xmlnode_set_attrib(node, attributes[i], attrib); g_free(attrib); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 05:59:52
|
Revision: 16830 Author: thekingant Date: 2006-08-17 22:59:47 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16830&view=rev Log Message: ----------- Patch from Henning Nor?\195?\169n to not show ICQ users as "pending" when they are away without a message Modified Paths: -------------- trunk/src/protocols/oscar/oscar.c Modified: trunk/src/protocols/oscar/oscar.c =================================================================== --- trunk/src/protocols/oscar/oscar.c 2006-08-18 05:58:17 UTC (rev 16829) +++ trunk/src/protocols/oscar/oscar.c 2006-08-18 05:59:47 UTC (rev 16830) @@ -2886,6 +2886,9 @@ gaim_status_set_attr_string(status, "message", message); g_free(message); } + else + /* Set an empty message so that we know not to show "pending" */ + gaim_status_set_attr_string(status, "message", message); gaim_blist_update_buddy_status(b, status); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 05:58:27
|
Revision: 16829 Author: thekingant Date: 2006-08-17 22:58:17 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16829&view=rev Log Message: ----------- Just rename connect to connectfunc. This is what it was like before my changes. Now I know why! Modified Paths: -------------- trunk/src/sslconn.c trunk/src/sslconn.h Modified: trunk/src/sslconn.c =================================================================== --- trunk/src/sslconn.c 2006-08-18 05:56:10 UTC (rev 16828) +++ trunk/src/sslconn.c 2006-08-18 05:58:17 UTC (rev 16829) @@ -46,7 +46,7 @@ ops = gaim_ssl_get_ops(); if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) || - (ops->connect == NULL) || (ops->close == NULL) || + (ops->connectfunc == NULL) || (ops->close == NULL) || (ops->read == NULL) || (ops->write == NULL)) { return FALSE; @@ -87,7 +87,7 @@ gsc->fd = source; ops = gaim_ssl_get_ops(); - (ops->connect)(gsc); + ops->connectfunc(gsc); } GaimSslConnection * @@ -177,7 +177,7 @@ gsc->fd = fd; ops = gaim_ssl_get_ops(); - (ops->connect)(gsc); + ops->connectfunc(gsc); return (GaimSslConnection *)gsc; } Modified: trunk/src/sslconn.h =================================================================== --- trunk/src/sslconn.h 2006-08-18 05:56:10 UTC (rev 16828) +++ trunk/src/sslconn.h 2006-08-18 05:58:17 UTC (rev 16829) @@ -68,7 +68,7 @@ { gboolean (*init)(void); void (*uninit)(void); - void (*connect)(GaimSslConnection *gsc); + void (*connectfunc)(GaimSslConnection *gsc); void (*close)(GaimSslConnection *gsc); size_t (*read)(GaimSslConnection *gsc, void *data, size_t len); size_t (*write)(GaimSslConnection *gsc, const void *data, size_t len); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <the...@us...> - 2006-08-18 05:56:14
|
Revision: 16828 Author: thekingant Date: 2006-08-17 22:56:10 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16828&view=rev Log Message: ----------- Get rid of an assertion failure when the selected icon is not a valid image Modified Paths: -------------- trunk/src/gtkstatusbox.c Modified: trunk/src/gtkstatusbox.c =================================================================== --- trunk/src/gtkstatusbox.c 2006-08-18 03:59:01 UTC (rev 16827) +++ trunk/src/gtkstatusbox.c 2006-08-18 05:56:10 UTC (rev 16828) @@ -1275,19 +1275,22 @@ if (status_box->icon_size != icon_alc.height) { + if (status_box->buddy_icon_hover) + g_object_unref(status_box->buddy_icon_hover); if ((status_box->buddy_icon_path != NULL) && (*status_box->buddy_icon_path != '\0')) { scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, icon_alc.height, icon_alc.width, FALSE, NULL); - if (status_box->buddy_icon_hover) - g_object_unref(status_box->buddy_icon_hover); - status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); - do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); - if (status_box->buddy_icon) - g_object_unref(status_box->buddy_icon); - status_box->buddy_icon = scaled; - gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); + if (scaled != NULL) + { + status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); + if (status_box->buddy_icon) + g_object_unref(status_box->buddy_icon); + status_box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); + } } status_box->icon_size = icon_alc.height; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dat...@us...> - 2006-08-18 03:59:07
|
Revision: 16827 Author: datallah Date: 2006-08-17 20:59:01 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16827&view=rev Log Message: ----------- A couple of leak fixes, some avoidance of unnecessary memory allocation/freeing and some cleanup. There are a lot fewer changes if you ignore space changes. Modified Paths: -------------- trunk/src/gtkblist.c Modified: trunk/src/gtkblist.c =================================================================== --- trunk/src/gtkblist.c 2006-08-18 03:49:38 UTC (rev 16826) +++ trunk/src/gtkblist.c 2006-08-18 03:59:01 UTC (rev 16827) @@ -120,7 +120,6 @@ static GaimGtkBuddyList *gtkblist = NULL; static gboolean gaim_gtk_blist_refresh_timer(GaimBuddyList *list); -static void gaim_gtk_blist_update_buddy_status_icon_key(GaimBlistNode *node, GaimStatusIconSize size); static void gaim_gtk_blist_update_buddy(GaimBuddyList *list, GaimBlistNode *node, gboolean statusChange); static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data); static void gaim_gtk_blist_update(GaimBuddyList *list, GaimBlistNode *node); @@ -141,7 +140,10 @@ GString *status_icon_key; }; +static void gaim_gtk_blist_update_buddy_status_icon_key(struct _gaim_gtk_blist_node *gtkbuddynode, + GaimBuddy *buddy, GaimStatusIconSize size); + static char dim_grey_string[8] = ""; static char *dim_grey() { @@ -167,7 +169,7 @@ else if (gtk_blist_obscured) { gtk_blist_obscured = FALSE; gaim_gtk_blist_refresh_timer(gaim_get_blist()); - } + } /* continue to handle event normally */ return FALSE; @@ -190,13 +192,13 @@ else gaim_prefs_set_bool("/gaim/gtk/blist/list_maximized", FALSE); } - + /* Refresh gtkblist if un-iconifying */ if (event->changed_mask & GDK_WINDOW_STATE_ICONIFIED){ if (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) gaim_gtk_blist_refresh_timer(gaim_get_blist()); } - + return FALSE; } @@ -873,15 +875,16 @@ GaimBlistNode *node; }; -static gboolean -scroll_to_expanded_cell(struct _expand *ex) +static gboolean +scroll_to_expanded_cell(gpointer data) { + struct _expand *ex = data; gtk_tree_view_scroll_to_cell(ex->treeview, ex->path, NULL, FALSE, 0, 0); gaim_gtk_blist_update_contact(NULL, ex->node); gtk_tree_path_free(ex->path); g_free(ex); - + return FALSE; } @@ -894,7 +897,7 @@ GtkTreePath *path; struct _expand *ex = g_new0(struct _expand, 1); - + if(!GAIM_BLIST_NODE_IS_CONTACT(node)) return; @@ -1675,7 +1678,7 @@ buddy->alias); } - str = g_string_append(str, "\r\n"); + g_string_append(str, "\r\n"); gtk_selection_data_set(data, gdk_atom_intern("application/x-im-contact", FALSE), @@ -2478,7 +2481,7 @@ { N_("/Buddies/Add C_hat..."), NULL, gaim_gtk_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD }, { N_("/Buddies/Add _Group..."), NULL, gaim_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD }, { "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL }, - { N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, + { N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, /* Accounts menu */ { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, @@ -2723,40 +2726,28 @@ static void g_string_destroy(GString *destroyable) { g_string_free(destroyable, TRUE); - return; } static void -gaim_gtk_blist_update_buddy_status_icon_key(GaimBlistNode *node, GaimStatusIconSize size) +gaim_gtk_blist_update_buddy_status_icon_key(struct _gaim_gtk_blist_node *gtkbuddynode, GaimBuddy *buddy, GaimStatusIconSize size) { - int i; - GaimAccount *account; - GaimPlugin *prpl; - GaimPluginProtocolInfo *prpl_info; GString *key = g_string_sized_new(16); - GaimBuddy *buddy; - const char *protoname = NULL; - struct _gaim_gtk_blist_node *gtknode = node->ui_data; - struct _gaim_gtk_blist_node *gtkbuddynode = NULL; - struct _emblem_data emblems[4] = {{NULL, 15, 15}, {NULL, 0, 15}, - {NULL, 0, 0}, {NULL, 15, 0}}; - buddy = (GaimBuddy*)node; - gtkbuddynode = node->ui_data; - - if (gtkbuddynode && gtkbuddynode->recent_signonoff) { - if (GAIM_BUDDY_IS_ONLINE(buddy)) + if(gtkbuddynode && gtkbuddynode->recent_signonoff) { + if(GAIM_BUDDY_IS_ONLINE(buddy)) g_string_printf(key, "login"); else g_string_printf(key, "logout"); } else { - GaimConversation *conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - gaim_buddy_get_name(buddy), - gaim_buddy_get_account(buddy)); + int i; + const char *protoname = NULL; + GaimAccount *account = buddy->account; + GaimPlugin *prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); + GaimPluginProtocolInfo *prpl_info; + GaimConversation *conv; + struct _emblem_data emblems[4] = {{NULL, 15, 15}, {NULL, 0, 15}, + {NULL, 0, 0}, {NULL, 15, 0}}; - account = buddy->account; - prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); - if(!prpl) return; @@ -2766,24 +2757,26 @@ protoname = prpl_info->list_icon(account, buddy); } if(prpl_info && prpl_info->list_emblems) { - if(gtknode) - prpl_info->list_emblems(buddy, &emblems[0].filename, - &emblems[1].filename, &emblems[2].filename, - &emblems[3].filename); + prpl_info->list_emblems(buddy, &emblems[0].filename, + &emblems[1].filename, &emblems[2].filename, + &emblems[3].filename); } g_string_assign(key, protoname); + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, + gaim_buddy_get_name(buddy), account); + if(conv != NULL) { GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv); - if(gtkconv != NULL && gaim_gtkconv_is_hidden(gtkconv)) { + if(gaim_gtkconv_is_hidden(gtkconv)) { /* add pending emblem */ if(size == GAIM_STATUS_ICON_SMALL) { - emblems[0].filename="pending"; + emblems[0].filename = "pending"; } else { - emblems[3].filename=emblems[2].filename; - emblems[2].filename="pending"; + emblems[3].filename = emblems[2].filename; + emblems[2].filename = "pending"; } } } @@ -2793,30 +2786,24 @@ emblems[1].filename = emblems[2].filename = emblems[3].filename = NULL; } - for(i=0; i<4; i++) { - if(emblems[i].filename) { + for(i = 0; i < 4; i++) { + if(emblems[i].filename) g_string_append_printf(key, "/%s", emblems[i].filename); - } } } - if (!GAIM_BUDDY_IS_ONLINE(buddy)) { - key = g_string_append(key, "/off"); - } else if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { - key = g_string_append(key, "/idle"); - } - if (!gaim_privacy_check(buddy->account, gaim_buddy_get_name(buddy))) { - key = g_string_append(key, "/priv"); - } + if (!GAIM_BUDDY_IS_ONLINE(buddy)) + g_string_append(key, "/off"); + else if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) + g_string_append(key, "/idle"); - if (gtkbuddynode) { - if (gtkbuddynode->status_icon_key) - g_string_free(gtkbuddynode->status_icon_key, TRUE); - gtkbuddynode->status_icon_key = g_string_new(key->str); - } + if (!gaim_privacy_check(buddy->account, gaim_buddy_get_name(buddy))) + g_string_append(key, "/priv"); - g_string_free(key, TRUE); - return; + if (gtkbuddynode->status_icon_key) + g_string_free(gtkbuddynode->status_icon_key, TRUE); + gtkbuddynode->status_icon_key = key; + } GdkPixbuf * @@ -2854,13 +2841,13 @@ (GEqualFunc)g_string_equal, (GDestroyNotify)g_string_destroy, (GDestroyNotify)gdk_pixbuf_unref); - + } else if (buddy && gtkbuddynode->status_icon_key && gtkbuddynode->status_icon_key->str) { key = g_string_new(gtkbuddynode->status_icon_key->str); /* Respect the size request given */ if (size == GAIM_STATUS_ICON_SMALL) { - key = g_string_append(key, "/tiny"); + g_string_append(key, "/tiny"); } scale = g_hash_table_lookup(status_icon_hash_table, key); @@ -2900,8 +2887,8 @@ /* Begin Generating Lookup Key */ if (buddy) { - gaim_gtk_blist_update_buddy_status_icon_key(node, size); - g_string_printf(key, "%s", strdup(gtkbuddynode->status_icon_key->str)); + gaim_gtk_blist_update_buddy_status_icon_key(gtkbuddynode, buddy, size); + g_string_assign(key, gtkbuddynode->status_icon_key->str); } /* There are only two options for chat or gaimdude - big or small */ else if (chat) { @@ -2923,14 +2910,14 @@ g_string_append_printf(key, "%s-chat", protoname); } else - key = g_string_append(key, "gaimdude"); + g_string_append(key, "gaimdude"); /* If the icon is small, we do not store this into the status_icon_key - * in the gtkbuddynode. This way we can respect the size value on cache + * in the gtkbuddynode. This way we can respect the size value on cache * lookup. Otherwise, different sized icons could not be stored easily. */ if (size == GAIM_STATUS_ICON_SMALL) { - key = g_string_append(key, "/tiny"); + g_string_append(key, "/tiny"); } /* End Generating Lookup Key */ @@ -2945,46 +2932,46 @@ /* Create a new composite icon */ - if(buddy) { - GaimAccount *account; - GaimPlugin *prpl; - GaimPluginProtocolInfo *prpl_info; - GaimConversation *conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - gaim_buddy_get_name(buddy), - gaim_buddy_get_account(buddy)); + if(buddy) { + GaimAccount *account; + GaimPlugin *prpl; + GaimPluginProtocolInfo *prpl_info; + GaimConversation *conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, + gaim_buddy_get_name(buddy), + gaim_buddy_get_account(buddy)); - account = buddy->account; + account = buddy->account; - prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); - if(!prpl) - return NULL; + prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); + if(!prpl) + return NULL; - prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); - if(prpl_info && prpl_info->list_icon) { - protoname = prpl_info->list_icon(account, buddy); - } - if(prpl_info && prpl_info->list_emblems) { - if(gtknode && !gtknode->recent_signonoff) - prpl_info->list_emblems(buddy, &emblems[0].filename, - &emblems[1].filename, &emblems[2].filename, - &emblems[3].filename); - } - - if(conv != NULL) { - GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv); - if(gtkconv != NULL && gaim_gtkconv_is_hidden(gtkconv)) { - /* add pending emblem */ - if(size == GAIM_STATUS_ICON_SMALL) { - emblems[0].filename="pending"; - } - else { - emblems[3].filename=emblems[2].filename; - emblems[2].filename="pending"; - } + if(prpl_info && prpl_info->list_icon) { + protoname = prpl_info->list_icon(account, buddy); + } + if(prpl_info && prpl_info->list_emblems) { + if(gtknode && !gtknode->recent_signonoff) + prpl_info->list_emblems(buddy, &emblems[0].filename, + &emblems[1].filename, &emblems[2].filename, + &emblems[3].filename); + } + + if(conv != NULL) { + GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv); + if(gtkconv != NULL && gaim_gtkconv_is_hidden(gtkconv)) { + /* add pending emblem */ + if(size == GAIM_STATUS_ICON_SMALL) { + emblems[0].filename="pending"; } + else { + emblems[3].filename=emblems[2].filename; + emblems[2].filename="pending"; + } } } + } if(size == GAIM_STATUS_ICON_SMALL) { scalesize = 15; @@ -2992,8 +2979,6 @@ emblems[1].filename = emblems[2].filename = emblems[3].filename = NULL; } - - if(buddy && GAIM_BUDDY_IS_ONLINE(buddy) && gtkbuddynode && gtkbuddynode->recent_signonoff) { filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "login.png", NULL); } else if(buddy && !GAIM_BUDDY_IS_ONLINE(buddy) && gtkbuddynode && gtkbuddynode->recent_signonoff) { @@ -3010,8 +2995,10 @@ status = gdk_pixbuf_new_from_file(filename, NULL); g_free(filename); - if(!status) + if(!status) { + g_string_free(key, TRUE); return NULL; + } scale = gdk_pixbuf_scale_simple(status, scalesize, scalesize, GDK_INTERP_BILINEAR); @@ -3079,7 +3066,7 @@ } } - /* Insert the new icon into the status icon hash table */ + /* Insert the new icon into the status icon hash table */ g_hash_table_insert (status_icon_hash_table, key, scale); gdk_pixbuf_ref(scale); @@ -3318,7 +3305,7 @@ gtkblist->selected_node = NULL; if (get_iter_from_node(node, &iter)) { gtk_tree_store_remove(gtkblist->treemodel, &iter); - if(update && (GAIM_BLIST_NODE_IS_CONTACT(node) || + if(update && (GAIM_BLIST_NODE_IS_CONTACT(node) || GAIM_BLIST_NODE_IS_BUDDY(node) || GAIM_BLIST_NODE_IS_CHAT(node))) { gaim_gtk_blist_update(list, node->parent); } @@ -3438,7 +3425,7 @@ return TRUE; } -static void +static void conversation_updated_cb(GaimConversation *conv, GaimConvUpdateType type, GaimGtkBuddyList *gtkblist) { @@ -3479,7 +3466,7 @@ } if(tooltip_text->len > 0) { /* get rid of the last newline */ - tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len -1); + g_string_truncate(tooltip_text, tooltip_text->len -1); img = gtk_image_new_from_stock(GAIM_STOCK_PENDING, GTK_ICON_SIZE_MENU); gtkblist->menutrayicon = gtk_event_box_new(); @@ -4040,7 +4027,7 @@ gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0); gtk_widget_set_name(gtkblist->statusbox, "gaim_gtkblist_statusbox"); gtk_widget_show(gtkblist->statusbox); - + /* set the Show Offline Buddies option. must be done * after the treeview or faceprint gets mad. -Robot101 */ @@ -4330,7 +4317,7 @@ return TRUE; } -/*This version of gaim_gtk_blist_update_group can take the original buddy +/*This version of gaim_gtk_blist_update_group can take the original buddy or a group, but has much better algorithmic performance with a pre-known buddy*/ static void gaim_gtk_blist_update_group(GaimBuddyList *list, GaimBlistNode *node) { @@ -4461,7 +4448,7 @@ cnode = node->parent; else cnode = node; - + g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT(cnode)); /* First things first, update the group */ @@ -4516,6 +4503,7 @@ { GaimBuddy *buddy; struct _gaim_gtk_blist_node *gtkparentnode; + struct _gaim_gtk_blist_node *gtknode = node->ui_data; g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); @@ -4525,7 +4513,8 @@ buddy = (GaimBuddy*)node; if (statusChange) - gaim_gtk_blist_update_buddy_status_icon_key(node, (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons") + gaim_gtk_blist_update_buddy_status_icon_key(gtknode, buddy, + (gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons") ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL)); /* First things first, update the contact */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dat...@us...> - 2006-08-18 03:50:03
|
Revision: 16826 Author: datallah Date: 2006-08-17 20:49:38 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16826&view=rev Log Message: ----------- Fix asserts at startup. Modified Paths: -------------- trunk/src/gtkstatusbox.c Modified: trunk/src/gtkstatusbox.c =================================================================== --- trunk/src/gtkstatusbox.c 2006-08-18 02:24:39 UTC (rev 16825) +++ trunk/src/gtkstatusbox.c 2006-08-18 03:49:38 UTC (rev 16826) @@ -1280,10 +1280,12 @@ { scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, icon_alc.height, icon_alc.width, FALSE, NULL); - g_object_unref(status_box->buddy_icon_hover); + if (status_box->buddy_icon_hover) + g_object_unref(status_box->buddy_icon_hover); status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); - g_object_unref(status_box->buddy_icon); + if (status_box->buddy_icon) + g_object_unref(status_box->buddy_icon); status_box->buddy_icon = scaled; gtk_image_set_from_pixbuf(GTK_IMAGE(status_box->icon), status_box->buddy_icon); } @@ -1444,14 +1446,18 @@ { if (box->buddy_icon != NULL) g_object_unref(box->buddy_icon); - scaled = gdk_pixbuf_new_from_file_at_scale(filename, - box->icon_size, box->icon_size, FALSE, NULL); - if (scaled != NULL) - { - box->buddy_icon_hover = gdk_pixbuf_copy(scaled); - do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); - box->buddy_icon = scaled; - gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon); + + /* This will get called before the box is shown and will not have a size */ + if (box->icon_size > 0) { + scaled = gdk_pixbuf_new_from_file_at_scale(filename, + box->icon_size, box->icon_size, FALSE, NULL); + if (scaled != NULL) + { + box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); + box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(GTK_IMAGE(box->icon), box->buddy_icon); + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dat...@us...> - 2006-08-18 02:24:46
|
Revision: 16825 Author: datallah Date: 2006-08-17 19:24:39 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16825&view=rev Log Message: ----------- deryni noticed a missing ')' (it turns out I had SASL disabled) Modified Paths: -------------- trunk/src/protocols/jabber/auth.c Modified: trunk/src/protocols/jabber/auth.c =================================================================== --- trunk/src/protocols/jabber/auth.c 2006-08-18 01:55:26 UTC (rev 16824) +++ trunk/src/protocols/jabber/auth.c 2006-08-18 02:24:39 UTC (rev 16825) @@ -265,7 +265,7 @@ */ if (mech && strlen(mech) > 0) { char *pos; - if ((pos = strstr(js->sasl_mechs->str, mech)) { + if ((pos = strstr(js->sasl_mechs->str, mech))) { g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(mech)); } again = TRUE; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sa...@us...> - 2006-08-18 01:55:35
|
Revision: 16824 Author: sadrul Date: 2006-08-17 18:55:26 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16824&view=rev Log Message: ----------- This is better. Modified Paths: -------------- trunk/src/util.c Modified: trunk/src/util.c =================================================================== --- trunk/src/util.c 2006-08-18 00:23:39 UTC (rev 16823) +++ trunk/src/util.c 2006-08-18 01:55:26 UTC (rev 16824) @@ -877,11 +877,11 @@ else if(IS_ENTITY(" ")) pln = " "; else if(IS_ENTITY("©")) - pln = "\251"; + pln = "\302\251"; /* or use g_unichar_to_utf8(0xa9); */ else if(IS_ENTITY(""")) pln = "\""; else if(IS_ENTITY("®")) - pln = "\256"; + pln = "\302\256"; /* or use g_unichar_to_utf8(0xae); */ else if(IS_ENTITY("'")) pln = "\'"; else if(*(text+1) == '#' && (sscanf(text, "&#%u;", £) == 1) && This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sa...@us...> - 2006-08-18 00:23:46
|
Revision: 16823 Author: sadrul Date: 2006-08-17 17:23:39 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16823&view=rev Log Message: ----------- Patch #1541744 ("Memleak"): "This plugs a possible memleak." The memleak would happen if you switch from an account with account-options to an account with none. Modified Paths: -------------- trunk/src/gtkaccount.c Modified: trunk/src/gtkaccount.c =================================================================== --- trunk/src/gtkaccount.c 2006-08-18 00:19:18 UTC (rev 16822) +++ trunk/src/gtkaccount.c 2006-08-18 00:23:39 UTC (rev 16823) @@ -646,6 +646,11 @@ dialog->protocol_frame = NULL; } + if (dialog->protocol_opt_entries != NULL) { + g_list_free(dialog->protocol_opt_entries); + dialog->protocol_opt_entries = NULL; + } + if (dialog->prpl_info == NULL || dialog->prpl_info->protocol_options == NULL) { @@ -669,11 +674,6 @@ gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); - if (dialog->protocol_opt_entries != NULL) { - g_list_free(dialog->protocol_opt_entries); - dialog->protocol_opt_entries = NULL; - } - for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next) { option = (GaimAccountOption *)l->data; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sa...@us...> - 2006-08-18 00:19:22
|
Revision: 16822 Author: sadrul Date: 2006-08-17 17:19:18 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16822&view=rev Log Message: ----------- Patch #1541742 ("Add boolean property \"iconsel\" for Statusbox"): "This adds a boolean property "iconsel" for statusbox. Setting the property to TRUE shows the icon-selector, setting it to FALSE removes it. It would allow plugins like mystatusbox to better control the statusboxes, especially the per-account ones." Modified Paths: -------------- trunk/src/gtkstatusbox.c Modified: trunk/src/gtkstatusbox.c =================================================================== --- trunk/src/gtkstatusbox.c 2006-08-18 00:15:25 UTC (rev 16821) +++ trunk/src/gtkstatusbox.c 2006-08-18 00:19:18 UTC (rev 16822) @@ -115,7 +115,8 @@ enum { PROP_0, - PROP_ACCOUNT + PROP_ACCOUNT, + PROP_ICON_SEL, }; GtkComboBoxClass *parent_class = NULL; @@ -163,6 +164,9 @@ case PROP_ACCOUNT: g_value_set_pointer(value, statusbox->account); break; + case PROP_ICON_SEL: + g_value_set_boolean(value, statusbox->icon_box != NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, psec); break; @@ -253,6 +257,9 @@ static void setup_icon_box(GtkGaimStatusBox *status_box) { + if (status_box->icon_box != NULL) + return; + if (status_box->account && !gaim_account_get_ui_bool(status_box->account, GAIM_GTK_UI, "use-global-buddyicon", TRUE)) { @@ -280,12 +287,54 @@ } static void +destroy_icon_box(GtkGaimStatusBox *statusbox) +{ + if (statusbox->icon_box == NULL) + return; + + gtk_widget_destroy(statusbox->icon_box); + gdk_cursor_unref(statusbox->hand_cursor); + gdk_cursor_unref(statusbox->arrow_cursor); + + g_object_unref(G_OBJECT(statusbox->buddy_icon)); + g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); + + if (statusbox->buddy_icon_sel) + gtk_widget_destroy(statusbox->buddy_icon_sel); + + g_free(statusbox->buddy_icon_path); + + statusbox->icon_box = NULL; + statusbox->buddy_icon_path = NULL; + statusbox->buddy_icon = NULL; + statusbox->buddy_icon_hover = NULL; + statusbox->hand_cursor = NULL; + statusbox->arrow_cursor = NULL; +} + +static void gtk_gaim_status_box_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GtkGaimStatusBox *statusbox = GTK_GAIM_STATUS_BOX(object); switch (param_id) { + case PROP_ICON_SEL: + if (g_value_get_boolean(value)) { + if (statusbox->account) { + GaimPlugin *plug = gaim_plugins_find_with_id(gaim_account_get_protocol_id(statusbox->account)); + if (plug) { + GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); + if (prplinfo && prplinfo->icon_spec.format != NULL) + setup_icon_box(statusbox); + } + } else { + setup_icon_box(statusbox); + } + } else { + destroy_icon_box(statusbox); + } + break; case PROP_ACCOUNT: statusbox->account = g_value_get_pointer(value); @@ -296,16 +345,9 @@ } if (statusbox->account) { - GaimPlugin *plug = gaim_plugins_find_with_id(gaim_account_get_protocol_id(statusbox->account)); - GaimPluginProtocolInfo *prplinfo = GAIM_PLUGIN_PROTOCOL_INFO(plug); - if (prplinfo && prplinfo->icon_spec.format != NULL) { - setup_icon_box(statusbox); - } statusbox->status_changed_signal = gaim_signal_connect(gaim_accounts_get_handle(), "account-status-changed", statusbox, GAIM_CALLBACK(account_status_changed_cb), statusbox); - } else { - setup_icon_box(statusbox); } gtk_gaim_status_box_regenerate(statusbox); @@ -365,6 +407,7 @@ combo_box_forall = container_class->forall; container_class->forall = gtk_gaim_status_box_forall; + container_class->remove = NULL; object_class = (GObjectClass *)klass; @@ -381,6 +424,15 @@ G_PARAM_READWRITE ) ); + g_object_class_install_property(object_class, + PROP_ICON_SEL, + g_param_spec_boolean("iconsel", + "Icon Selector", + "Whether the icon selector should be displayed or not.", + FALSE, + G_PARAM_READWRITE + ) + ); } /** @@ -1005,6 +1057,7 @@ gaim_account_set_buddy_icon(box->account, icon); g_free(icon); gaim_account_set_ui_bool(box->account, GAIM_GTK_UI, "use-global-buddyicon", FALSE); + gaim_account_set_ui_string(box->account, GAIM_GTK_UI, "non-global-buddyicon", icon); } } } else { @@ -1251,7 +1304,8 @@ GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->vbox, event); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->toggle_button, event); - gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); + if (status_box->icon_box) + gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); return FALSE; } @@ -1278,13 +1332,15 @@ GtkWidget * gtk_gaim_status_box_new() { - return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", NULL, NULL); + return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", NULL, + "iconsel", TRUE, NULL); } GtkWidget * gtk_gaim_status_box_new_with_account(GaimAccount *account) { - return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, NULL); + return g_object_new(GTK_GAIM_TYPE_STATUS_BOX, "account", account, + "iconsel", TRUE, NULL); } /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sa...@us...> - 2006-08-18 00:15:29
|
Revision: 16821 Author: sadrul Date: 2006-08-17 17:15:25 -0700 (Thu, 17 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16821&view=rev Log Message: ----------- Patch #1523103 ("Improved markup processing"): "This patch tries to handle all the html-entities (including stuff like ® and &#xx;) in gaim_markup_strip_html and gaim_unescape_html. This also allows fixing the issue with libxml2 where & was being converted to &." Modified Paths: -------------- trunk/src/util.c trunk/src/xmlnode.c Modified: trunk/src/util.c =================================================================== --- trunk/src/util.c 2006-08-17 23:58:58 UTC (rev 16820) +++ trunk/src/util.c 2006-08-18 00:15:25 UTC (rev 16821) @@ -854,6 +854,55 @@ /************************************************************************** * Markup Functions **************************************************************************/ + +/* Returns a NULL-terminated string after unescaping an entity + * (eg. &, < & etc.) starting at s. Returns NULL on failure.*/ +static const char * +detect_entity(const char *text, int *length) +{ + const char *pln; + int len, pound; + + if (!text || *text != '&') + return NULL; + +#define IS_ENTITY(s) (!g_ascii_strncasecmp(text, s, (len = sizeof(s) - 1))) + + if(IS_ENTITY("&")) + pln = "&"; + else if(IS_ENTITY("<")) + pln = "<"; + else if(IS_ENTITY(">")) + pln = ">"; + else if(IS_ENTITY(" ")) + pln = " "; + else if(IS_ENTITY("©")) + pln = "\251"; + else if(IS_ENTITY(""")) + pln = "\""; + else if(IS_ENTITY("®")) + pln = "\256"; + else if(IS_ENTITY("'")) + pln = "\'"; + else if(*(text+1) == '#' && (sscanf(text, "&#%u;", £) == 1) && + pound != 0 && *(text+3+(gint)log10(pound)) == ';') { + static char buf[7]; + int buflen = g_unichar_to_utf8((gunichar)pound, buf); + buf[buflen] = '\0'; + pln = buf; + + len = 2; + while(isdigit((gint) text[len])) len++; + if(text[len] == ';') len++; + } + else + return NULL; + + if (length) + *length = len; + return pln; +} + gboolean gaim_markup_find_tag(const char *needle, const char *haystack, const char **start, const char **end, GData **attributes) @@ -1443,44 +1492,10 @@ } } else if(*c == '&') { char buf[7]; - char *pln; - int len = 1; - guint pound; - if(!g_ascii_strncasecmp(c, "&", 5)) { - pln = "&"; - len = 5; - } else if(!g_ascii_strncasecmp(c, "<", 4)) { - pln = "<"; - len = 4; - } else if(!g_ascii_strncasecmp(c, ">", 4)) { - pln = ">"; - len = 4; - } else if(!g_ascii_strncasecmp(c, " ", 6)) { - pln = " "; - len = 6; - } else if(!g_ascii_strncasecmp(c, "©", 6)) { - pln = "©"; - len = 6; - } else if(!g_ascii_strncasecmp(c, """, 6)) { - pln = "\""; - len = 6; - } else if(!g_ascii_strncasecmp(c, "®", 5)) { - pln = "®"; - len = 5; - } else if(!g_ascii_strncasecmp(c, "'", 6)) { - pln = "\'"; - len = 6; - } else if(*(c+1) == '#' && (sscanf(c, "&#%u;", £) == 1) && - pound != 0 && *(c+3+(gint)log10(pound)) == ';') { - int buflen = g_unichar_to_utf8((gunichar)pound, buf); - buf[buflen] = '\0'; - pln = buf; + const char *pln; + int len; - - len = 2; - while(isdigit((gint) c [len])) len++; - if(c [len] == ';') len++; - } else { + if ((pln = detect_entity(c, &len)) == NULL) { len = 1; g_snprintf(buf, sizeof(buf), "%c", *c); pln = buf; @@ -1522,11 +1537,11 @@ char * gaim_markup_strip_html(const char *str) { - int i, j, k; + int i, j, k, entlen; gboolean visible = TRUE; gboolean closing_td_p = FALSE; gchar *str2; - const gchar *cdata_close_tag = NULL; + const gchar *cdata_close_tag = NULL, *ent; gchar *href = NULL; int href_st = 0; @@ -1685,44 +1700,14 @@ visible = TRUE; } - /* XXX: This sucks. We need to be un-escaping all entities, which - * includes these, as well as the &#num; ones */ - - if (str2[i] == '&' && strncasecmp(str2 + i, """, 6) == 0) + if (str2[i] == '&' && (ent = detect_entity(str2 + i, &entlen)) != NULL) { - str2[j++] = '\"'; - i = i + 5; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, "&", 5) == 0) - { - str2[j++] = '&'; - i = i + 4; + while (*ent) + str2[j++] = *ent++; + i += entlen - 1; continue; } - if (str2[i] == '&' && strncasecmp(str2 + i, "<", 4) == 0) - { - str2[j++] = '<'; - i = i + 3; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, ">", 4) == 0) - { - str2[j++] = '>'; - i = i + 3; - continue; - } - - if (str2[i] == '&' && strncasecmp(str2 + i, "'", 6) == 0) - { - str2[j++] = '\''; - i = i + 5; - continue; - } - if (visible) str2[j++] = g_ascii_isspace(str2[i])? ' ': str2[i]; } @@ -2026,41 +2011,28 @@ char * gaim_unescape_html(const char *html) { - const char *c; - GString *ret; + if (html != NULL) { + const char *c = html; + GString *ret = g_string_new(""); + while (*c) { + int len; + const char *ent; - if (html == NULL) - return NULL; - - c = html; - ret = g_string_new(""); - while (*c) { - if (!strncmp(c, "&", 5)) { - ret = g_string_append_c(ret, '&'); - c += 5; - } else if (!strncmp(c, "<", 4)) { - ret = g_string_append_c(ret, '<'); - c += 4; - } else if (!strncmp(c, ">", 4)) { - ret = g_string_append_c(ret, '>'); - c += 4; - } else if (!strncmp(c, """, 6)) { - ret = g_string_append_c(ret, '"'); - c += 6; - } else if (!strncmp(c, "'", 6)) { - ret = g_string_append_c(ret, '\''); - c += 6; - } else if (!strncmp(c, "<br>", 4)) { - ret = g_string_append_c(ret, '\n'); - c += 4; - } else { - ret = g_string_append_c(ret, *c); - c++; + if ((ent = detect_entity(c, &len)) != NULL) { + ret = g_string_append(ret, ent); + c += len; + } else if (!strncmp(c, "<br>", 4)) { + ret = g_string_append_c(ret, '\n'); + c += 4; + } else { + ret = g_string_append_c(ret, *c); + c++; + } } + return g_string_free(ret, FALSE); } - return g_string_free(ret, FALSE); - + return NULL; } char * @@ -3998,4 +3970,3 @@ return buf; } - Modified: trunk/src/xmlnode.c =================================================================== --- trunk/src/xmlnode.c 2006-08-17 23:58:58 UTC (rev 16820) +++ trunk/src/xmlnode.c 2006-08-18 00:15:25 UTC (rev 16821) @@ -35,6 +35,7 @@ #include <string.h> #include <glib.h> +#include "util.h" #include "xmlnode.h" #ifdef _WIN32 @@ -406,6 +407,11 @@ char *attrib = g_malloc(attrib_len + 1); memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; +#ifdef HAVE_LIBXML + char *txt = attrib; + attrib = gaim_unescape_html(txt); + g_free(txt); +#endif xmlnode_set_attrib(node, attributes[i], attrib); g_free(attrib); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |