diff --git a/configure b/configure
index edc4adb..1b1336d 100755
--- a/configure
+++ b/configure
@@ -349,10 +349,10 @@ detect_resolv_static()
TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX)
ret=1
for i in $systemlibdirs; do
- if [ -f $i/libresolv.a ]; then
+ if [ -f $i/libresolv.so ]; then
echo "$RESOLV_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
if [ "$?" = "0" ]; then
- echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
+ echo 'EFLAGS+=-lresolv' >> Makefile.settings
ret=0
fi
fi
diff --git a/lib/misc.c b/lib/misc.c
index 05192d9..556fe1a 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -1,8 +1,8 @@
- /********************************************************************\
- * BitlBee -- An IRC to other IM-networks gateway *
- * *
- * Copyright 2002-2006 Wilmer van der Gaast and others *
- \********************************************************************/
+/********************************************************************\
+* BitlBee -- An IRC to other IM-networks gateway *
+* *
+* Copyright 2002-2006 Wilmer van der Gaast and others *
+\********************************************************************/
/*
* Various utility functions. Some are copied from Gaim to support the
@@ -30,6 +30,12 @@
Suite 330, Boston, MA 02111-1307 USA
*/
+#undef TEST
+
+#ifdef TEST
+#define HAVE_RESOLV_A
+#endif
+
#define BITLBEE_CORE
#include "nogaim.h"
#include "base64.h"
@@ -42,13 +48,17 @@
#include <time.h>
#ifdef HAVE_RESOLV_A
-#include <arpa/nameser.h>
#include <resolv.h>
#endif
#include "md5.h"
#include "ssl_client.h"
+/* Not every installation has gotten around to supporting SRVs yet...*/
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
void strip_linefeed(gchar *text)
{
int i, j;
@@ -514,66 +524,6 @@ int bool2int( char *value )
return 0;
}
-struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain )
-{
- struct ns_srv_reply **replies = NULL;
-#ifdef HAVE_RESOLV_A
- struct ns_srv_reply *reply = NULL;
- char name[1024];
- unsigned char querybuf[1024];
- const unsigned char *buf;
- ns_msg nsh;
- ns_rr rr;
- int i, n, len, size;
-
- g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
-
- if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 )
- return NULL;
-
- if( ns_initparse( querybuf, size, &nsh ) != 0 )
- return NULL;
-
- n = 0;
- while( ns_parserr( &nsh, ns_s_an, n, &rr ) == 0 )
- {
- size = ns_rr_rdlen( rr );
- buf = ns_rr_rdata( rr );
-
- len = 0;
- for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
- len += buf[i] + 1;
-
- if( i > size )
- break;
-
- reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
- memcpy( reply->name, buf + 7, len );
-
- for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
- reply->name[i] = '.';
-
- if( i > len )
- {
- g_free( reply );
- break;
- }
-
- reply->prio = ( buf[0] << 8 ) | buf[1];
- reply->weight = ( buf[2] << 8 ) | buf[3];
- reply->port = ( buf[4] << 8 ) | buf[5];
-
- n ++;
- replies = g_renew( struct ns_srv_reply *, replies, n + 1 );
- replies[n-1] = reply;
- }
- if( replies )
- replies[n] = NULL;
-#endif
-
- return replies;
-}
-
void srv_free( struct ns_srv_reply **srv )
{
int i;
@@ -586,6 +536,119 @@ void srv_free( struct ns_srv_reply **srv )
g_free( srv );
}
+static int srv_compare(const void *a, const void *b) {
+ int prio;
+ const struct ns_srv_reply *sa = *(struct ns_srv_reply **) a;
+ const struct ns_srv_reply *sb = *(struct ns_srv_reply **) b;
+
+ prio = sa->prio - sb->prio;
+ if (prio == 0) {
+ /* Place weight 0 entries first. */
+ if (sa->weight == 0) return -1;
+ if (sb->weight == 0) return 1;
+ }
+
+ return prio;
+}
+
+struct ns_srv_reply **srv_lookup(char *service, char *protocol, char *domain) {
+ struct ns_srv_reply **results = NULL;
+ struct ns_srv_reply *reply = NULL;
+ char name[1024];
+
+ /* PACKETSZ is a maximum packet size and
+ defined in arpa/nameser_compat.h as 512 */
+ unsigned char answer[PACKETSZ];
+ int len;
+ HEADER *header;
+ unsigned char *p;
+ unsigned char *end;
+ unsigned int count;
+ size_t n;
+
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength;
+
+ g_snprintf(name, sizeof(name), "_%s._%s.%s", service, protocol, domain);
+
+ len = res_query(name, C_IN, T_SRV, answer, PACKETSZ);
+ if (len == -1) {
+ goto fail;
+ }
+
+ header = (HEADER *) answer;
+ p = answer + sizeof(HEADER);
+ end = answer + len;
+
+ if (header->rcode != NOERROR) {
+ goto fail;
+ }
+
+ len = dn_skipname(p, end);
+ if (len == -1) {
+ goto fail;
+ }
+ p += len + QFIXEDSZ;
+
+ count = ntohs(header->ancount);
+
+ results = g_new(struct ns_srv_reply *, count + 1);
+
+ n = 0;
+ while (count-- > 0 && p < end) {
+ len = dn_skipname(p, end);
+ if (len == -1) {
+ goto fail;
+ }
+ p += len;
+
+ GETSHORT(type, p);
+ GETSHORT(class, p);
+ GETLONG(ttl, p);
+ GETSHORT(rdlength, p);
+
+ if (type != T_SRV || class != C_IN) {
+ p += rdlength;
+ continue;
+ }
+
+ /* This is an overestimate of the needed size. */
+ reply = g_malloc(sizeof(struct ns_srv_reply) + rdlength + 1);
+
+ GETSHORT(reply->prio, p);
+ GETSHORT(reply->weight, p);
+ GETSHORT(reply->port, p);
+
+ len = dn_expand(answer, end, p, reply->name, rdlength + 1);
+ if (len == -1) {
+ g_free(reply);
+ goto fail;
+ }
+ p += len;
+
+ results[n++] = reply;
+ }
+
+ results[n] = NULL;
+
+ /* Order by priority. */
+ qsort(results, n, sizeof(struct ns_srv_reply *), srv_compare);
+
+ return results;
+
+fail:
+ if (results) {
+ while (n-- > 0) {
+ g_free(results[n]);
+ }
+ g_free(results);
+ }
+
+ return NULL;
+}
+
/* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */
char *word_wrap( const char *msg, int line_len )
{
@@ -728,3 +791,22 @@ char **split_command_parts( char *command )
return cmd;
}
+
+#ifdef TEST
+int main() {
+ struct ns_srv_reply **srv;
+ int i;
+
+ srv = srv_lookup("xmpp-client", "tcp", "jabber.org");
+ for (i = 0; srv[i]; ++i) {
+ printf("priority=%hu\n", srv[i]->prio);
+ printf("weight=%hu\n", srv[i]->weight);
+ printf("port=%hu\n", srv[i]->port);
+ printf("target=%s\n", srv[i]->name);
+ printf("\n");
+ }
+ srv_free(srv);
+
+ return 0;
+}
+#endif /* TEST */