aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitlbee.h4
-rw-r--r--debian/changelog7
-rw-r--r--debian/control6
-rwxr-xr-xdebian/rules4
-rw-r--r--doc/CHANGES14
-rw-r--r--doc/bitlbee.85
-rw-r--r--doc/user-guide/commands.xml2
-rw-r--r--doc/user-guide/quickstart.xml4
-rw-r--r--irc_commands.c20
-rw-r--r--lib/misc.c5
-rw-r--r--lib/xmltree.c22
-rw-r--r--protocols/jabber/conference.c4
-rw-r--r--protocols/jabber/iq.c1
-rw-r--r--protocols/msn/passport.c4
-rw-r--r--protocols/msn/sb.c49
-rw-r--r--protocols/oscar/oscar.c148
-rw-r--r--protocols/twitter/twitter.c34
-rw-r--r--protocols/twitter/twitter.h5
-rw-r--r--protocols/twitter/twitter_http.c103
-rw-r--r--protocols/twitter/twitter_http.h4
-rw-r--r--protocols/twitter/twitter_lib.c69
-rw-r--r--protocols/twitter/twitter_lib.h54
-rw-r--r--protocols/yahoo/yahoo.c9
23 files changed, 260 insertions, 317 deletions
diff --git a/bitlbee.h b/bitlbee.h
index f4e03d76..2f4fa6be 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -34,10 +34,10 @@
#define _WIN32_WINNT 0x0501
#define PACKAGE "BitlBee"
-#define BITLBEE_VERSION "1.2.6a"
+#define BITLBEE_VERSION "1.2.7"
#define VERSION BITLBEE_VERSION
#define BITLBEE_VER(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#define BITLBEE_VERSION_CODE BITLBEE_VER(1, 2, 6)
+#define BITLBEE_VERSION_CODE BITLBEE_VER(1, 2, 7)
#define MAX_STRING 511
diff --git a/debian/changelog b/debian/changelog
index 56d0a551..ca592229 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+bitlbee (1.2.7-1) unstable; urgency=high
+
+ * New upstream version.
+ * Fixes MSN Messenger login issues, so uploading at high priority.
+
+ -- Wilmer van der Gaast <wilmer@gaast.net> Sat, 15 May 2010 16:15:57 +0100
+
bitlbee (1.2.6a-1) unstable; urgency=low
* New upstream version.
diff --git a/debian/control b/debian/control
index 86488c8a..25a90506 100644
--- a/debian/control
+++ b/debian/control
@@ -14,13 +14,15 @@ Architecture: any
Depends: ${shlibs:Depends}, adduser, net-tools, ${debconf-depends}, debianutils (>= 1.16)
Description: An IRC to other chat networks gateway
This program can be used as an IRC server which forwards everything you
- say to people on other chat networks: Jabber, ICQ, AIM, MSN and Yahoo.
+ say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
+ Twitter.
Package: bitlbee-dev
Architecture: all
Depends: bitlbee (>= ${source:Version}), bitlbee (<< ${source:Version}.1~)
Description: An IRC to other chat networks gateway
This program can be used as an IRC server which forwards everything you
- say to people on other chat networks: Jabber, ICQ, AIM, MSN and Yahoo.
+ say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
+ Twitter.
.
This package holds development stuff for compiling plug-ins.
diff --git a/debian/rules b/debian/rules
index 0c656fd8..ae6463fc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -98,7 +98,11 @@ binary-indep: install-indep
cd debian/bitlbee-dev; \
find usr -type f -exec md5sum {} \; > DEBIAN/md5sums
+ifdef BITLBEE_FORCE_VERSION
dpkg-gencontrol -ldebian/changelog -isp -pbitlbee-dev -Pdebian/bitlbee-dev -v1:$(BITLBEE_VERSION)-0
+else
+ dpkg-gencontrol -ldebian/changelog -isp -pbitlbee-dev -Pdebian/bitlbee-dev
+endif
dpkg --build debian/bitlbee-dev ..
diff --git a/doc/CHANGES b/doc/CHANGES
index 45b16e28..7359a050 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -3,6 +3,20 @@ found in the bzr commit logs, for example you can try:
http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
+Version 1.2.7:
+- Fixed problems with MSN Messenger authentication. ("Could not parse
+ Passport server response")
+- Fixed broken typing notifications when talking to GTalk contacts.
+- Fixed an issue with non-anonymous Jabber chatrooms polluting the nick
+ namespace, sometimes generating odd warning messages.
+- Restored ability to start groupchats on ICQ.
+- Added show_offline setting that will also show offline contacts in the
+ control channel.
+- OAuth support for Twitter: This means the module will keep working after
+ June (this also changes "via API" under your tweets into "via BitlBee").
+
+Finished 15 May 2010
+
Version 1.2.6a:
- Fixed a typo that renders the Twitter groupchat mode unusable. A last-
minute change that came a few minutes late.
diff --git a/doc/bitlbee.8 b/doc/bitlbee.8
index 9e634844..36576e59 100644
--- a/doc/bitlbee.8
+++ b/doc/bitlbee.8
@@ -38,9 +38,8 @@ BitlBee \- IRC gateway to IM chat networks
BitlBee is an IRC daemon that can talk to instant messaging
networks and acts as a gateway. Users can connect to the server
with any normal IRC client and see their 'buddy list' in
-&bitlbee. BitlBee's protocol support is based on the gaim
-protocol plugins. BitlBee currently supports Oscar (aim and icq),
-MSN, Jabber and Yahoo.
+&bitlbee. It currently supports Oscar (AIM and ICQ),
+MSN, Jabber, Yahoo! and Twitter.
\fBbitlbee\fP should be called by
.BR inetd (8),
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index ba2b4e70..15ed4c34 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -619,7 +619,7 @@
</bitlbee-setting>
<bitlbee-setting name="ignore_auth_requests" type="boolean" scope="account">
- <default>true</default>
+ <default>false</default>
<description>
<para>
diff --git a/doc/user-guide/quickstart.xml b/doc/user-guide/quickstart.xml
index 0539a7c7..80c16ffb 100644
--- a/doc/user-guide/quickstart.xml
+++ b/doc/user-guide/quickstart.xml
@@ -2,7 +2,7 @@
<title>Quickstart</title>
<para>
-Welcome to BitlBee, your IRC gateway to ICQ, MSN, AOL, Jabber and Yahoo Instant Messaging Systems.
+Welcome to BitlBee, your IRC gateway to ICQ, MSN, AOL, Jabber, Yahoo! and Twitter.
</para>
<para>
@@ -42,7 +42,7 @@ For instance, suppose you have a Jabber account at jabber.org with handle <empha
</ircexample>
<para>
-Other available IM protocols are msn, oscar, and yahoo. OSCAR is the protocol used by ICQ and AOL. For more information about the <emphasis>account add</emphasis> command, see <emphasis>help account add</emphasis>.
+Other available IM protocols are msn, oscar, yahoo and twitter. OSCAR is the protocol used by ICQ and AOL. For more information about the <emphasis>account add</emphasis> command, see <emphasis>help account add</emphasis>.
</para>
<para>
diff --git a/irc_commands.c b/irc_commands.c
index 319d549a..7a286ce2 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -72,19 +72,29 @@ static void irc_cmd_user( irc_t *irc, char **cmd )
static void irc_cmd_nick( irc_t *irc, char **cmd )
{
- if( irc->nick )
+ if( irc->status & USTATUS_IDENTIFIED && irc->nick )
{
- irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
+ irc_reply( irc, 438, "%s %s :You can only change your nick if you're not "
+ "logged in (i.e. pre-identify)", irc->nick, cmd[1] );
}
/* This is not clean, but for now it'll have to be like this... */
- else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
+ else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) || ( user_find( irc, cmd[1] ) != NULL ) )
{
- irc_reply( irc, 433, ":This nick is already in use" );
+ irc_reply( irc, 433, "%s :This nick is already in use", cmd[1] );
}
else if( !nick_ok( cmd[1] ) )
{
/* [SH] Invalid characters. */
- irc_reply( irc, 432, ":This nick contains invalid characters" );
+ irc_reply( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
+ }
+ else if(irc->nick)
+ {
+ if( user_find( irc, irc->nick ) )
+ user_rename(irc, irc->nick, cmd[1]);
+
+ irc_write( irc, ":%s!%s@%s NICK %s", irc->nick, irc->user, irc->host, cmd[1] );
+ g_free(irc->nick);
+ irc->nick = g_strdup( cmd[1] );
}
else
{
diff --git a/lib/misc.c b/lib/misc.c
index c56b31f3..d77972e3 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -153,11 +153,11 @@ static const htmlentity_t ent[] =
void strip_html( char *in )
{
char *start = in;
- char *out = g_malloc( strlen( in ) + 1 );
+ char out[strlen(in)+1];
char *s = out, *cs;
int i, matched;
- memset( out, 0, strlen( in ) + 1 );
+ memset( out, 0, sizeof( out ) );
while( *in )
{
@@ -219,7 +219,6 @@ void strip_html( char *in )
}
strcpy( start, out );
- g_free( out );
}
char *escape_html( const char *html )
diff --git a/lib/xmltree.c b/lib/xmltree.c
index 67fe46e1..31f8ee9c 100644
--- a/lib/xmltree.c
+++ b/lib/xmltree.c
@@ -448,7 +448,11 @@ struct xt_node *xt_find_node( struct xt_node *node, const char *name )
{
while( node )
{
- if( g_strcasecmp( node->name, name ) == 0 )
+ char *colon;
+
+ if( g_strcasecmp( node->name, name ) == 0 ||
+ ( ( colon = strchr( node->name, ':' ) ) &&
+ g_strcasecmp( colon + 1, name ) == 0 ) )
break;
node = node->next;
@@ -460,6 +464,7 @@ struct xt_node *xt_find_node( struct xt_node *node, const char *name )
char *xt_find_attr( struct xt_node *node, const char *key )
{
int i;
+ char *colon;
if( !node )
return NULL;
@@ -468,6 +473,21 @@ char *xt_find_attr( struct xt_node *node, const char *key )
if( g_strcasecmp( node->attr[i].key, key ) == 0 )
break;
+ /* This is an awful hack that only takes care of namespace prefixes
+ inside a tag. Since IMHO excessive namespace usage in XMPP is
+ massive overkill anyway (this code exists for almost four years
+ now and never really missed it): Meh. */
+ if( !node->attr[i].key && strcmp( key, "xmlns" ) == 0 &&
+ ( colon = strchr( node->name, ':' ) ) )
+ {
+ *colon = '\0';
+ for( i = 0; node->attr[i].key; i ++ )
+ if( strncmp( node->attr[i].key, "xmlns:", 6 ) == 0 &&
+ strcmp( node->attr[i].key + 6, node->name ) == 0 )
+ break;
+ *colon = ':';
+ }
+
return node->attr[i].value;
}
diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c
index f434c58a..affe8aef 100644
--- a/protocols/jabber/conference.c
+++ b/protocols/jabber/conference.c
@@ -271,8 +271,10 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu
bud->flags |= JBFLAG_IS_ANONYMOUS;
}
- if( bud != jc->me )
+ if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
{
+ /* If JIDs are anonymized, add them to the local
+ list for the duration of this chat. */
imcb_add_buddy( ic, bud->ext_jid, NULL );
imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource );
}
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index 1b76a761..95b21e1e 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -126,7 +126,6 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
if( !( c = xt_find_node( node->children, "query" ) ) ||
!( s = xt_find_attr( c, "xmlns" ) ) )
{
- imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
return XT_HANDLED;
}
diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c
index 565d15f3..7c896db1 100644
--- a/protocols/msn/passport.c
+++ b/protocols/msn/passport.c
@@ -144,7 +144,9 @@ static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data
struct msn_auth_data *mad = data;
char *s;
- if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 )
+ if( ( s = xt_find_attr( node, "Id" ) ) &&
+ ( strncmp( s, "Compact", 7 ) == 0 ||
+ strncmp( s, "PPToken", 7 ) == 0 ) )
mad->token = g_memdup( node->text, node->text_len + 1 );
return XT_HANDLED;
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c
index e2ee8570..49eed601 100644
--- a/protocols/msn/sb.c
+++ b/protocols/msn/sb.c
@@ -327,9 +327,13 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c
struct im_connection *ic = sb->ic;
struct msn_data *md = ic->proto_data;
- if( msn_handler( sb->handler ) == -1 )
+ if( msn_handler( sb->handler ) != -1 )
+ return TRUE;
+
+ if( sb->msgq != NULL )
{
time_t now = time( NULL );
+ char buf[1024];
if( now - md->first_sb_failure > 600 )
{
@@ -346,37 +350,28 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c
imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
"There might be problems delivering your messages." );
- if( sb->msgq != NULL )
+ if( md->msgq == NULL )
{
- char buf[1024];
-
- if( md->msgq == NULL )
- {
- md->msgq = sb->msgq;
- }
- else
- {
- GSList *l;
-
- for( l = md->msgq; l->next; l = l->next );
- l->next = sb->msgq;
- }
- sb->msgq = NULL;
+ md->msgq = sb->msgq;
+ }
+ else
+ {
+ GSList *l;
- debug( "Moved queued messages back to the main queue, creating a new switchboard to retry." );
- g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
- if( !msn_write( ic, buf, strlen( buf ) ) )
- return FALSE;
+ for( l = md->msgq; l->next; l = l->next );
+ l->next = sb->msgq;
}
+ sb->msgq = NULL;
- msn_sb_destroy( sb );
-
- return FALSE;
- }
- else
- {
- return TRUE;
+ debug( "Moved queued messages back to the main queue, "
+ "creating a new switchboard to retry." );
+ g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
+ if( !msn_write( ic, buf, strlen( buf ) ) )
+ return FALSE;
}
+
+ msn_sb_destroy( sb );
+ return FALSE;
}
static int msn_sb_command( gpointer data, char **cmd, int num_parts )
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index e0c32257..9f33f320 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -204,7 +204,6 @@ static int gaim_parse_buddyrights(aim_session_t *, aim_frame_t *, ...);
static int gaim_parse_locerr (aim_session_t *, aim_frame_t *, ...);
static int gaim_icbm_param_info (aim_session_t *, aim_frame_t *, ...);
static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...);
-static int gaim_memrequest (aim_session_t *, aim_frame_t *, ...);
static int gaim_selfinfo (aim_session_t *, aim_frame_t *, ...);
static int gaim_offlinemsg (aim_session_t *, aim_frame_t *, ...);
static int gaim_offlinemsgdone (aim_session_t *, aim_frame_t *, ...);
@@ -569,7 +568,6 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR, gaim_parse_genericerr, 0);
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ERROR, gaim_parse_genericerr, 0);
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BOS, AIM_CB_BOS_ERROR, gaim_parse_genericerr, 0);
- aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x1f, gaim_memrequest, 0);
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SELFINFO, gaim_selfinfo, 0);
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
@@ -603,143 +601,9 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {
return 1;
}
-struct pieceofcrap {
- struct im_connection *ic;
- unsigned long offset;
- unsigned long len;
- char *modname;
- int fd;
- aim_conn_t *conn;
- unsigned int inpa;
-};
-
-static gboolean damn_you(gpointer data, gint source, b_input_condition c)
-{
- struct pieceofcrap *pos = data;
- struct oscar_data *od = pos->ic->proto_data;
- char in = '\0';
- int x = 0;
- unsigned char m[17];
-
- while (read(pos->fd, &in, 1) == 1) {
- if (in == '\n')
- x++;
- else if (in != '\r')
- x = 0;
- if (x == 2)
- break;
- in = '\0';
- }
- if (in != '\n') {
- imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM."
- " You may be disconnected shortly.");
- b_event_remove(pos->inpa);
- closesocket(pos->fd);
- g_free(pos);
- return FALSE;
- }
- /* [WvG] Wheeeee! Who needs error checking anyway? ;-) */
- read(pos->fd, m, 16);
- m[16] = '\0';
- b_event_remove(pos->inpa);
- closesocket(pos->fd);
- aim_sendmemblock(od->sess, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
- g_free(pos);
-
- return FALSE;
-}
-
-static gboolean straight_to_hell(gpointer data, gint source, b_input_condition cond) {
- struct pieceofcrap *pos = data;
- char buf[BUF_LONG];
-
- if (source < 0) {
- imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM."
- " You may be disconnected shortly.");
- if (pos->modname)
- g_free(pos->modname);
- g_free(pos);
- return FALSE;
- }
-
- g_snprintf(buf, sizeof(buf), "GET " AIMHASHDATA
- "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
- pos->offset, pos->len, pos->modname ? pos->modname : "");
- write(pos->fd, buf, strlen(buf));
- if (pos->modname)
- g_free(pos->modname);
- pos->inpa = b_input_add(pos->fd, GAIM_INPUT_READ, damn_you, pos);
- return FALSE;
-}
-
/* size of icbmui.ocm, the largest module in AIM 3.5 */
#define AIM_MAX_FILE_SIZE 98304
-int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) {
- va_list ap;
- struct pieceofcrap *pos;
- guint32 offset, len;
- char *modname;
- int fd;
-
- va_start(ap, fr);
- offset = (guint32)va_arg(ap, unsigned long);
- len = (guint32)va_arg(ap, unsigned long);
- modname = va_arg(ap, char *);
- va_end(ap);
-
- if (len == 0) {
- aim_sendmemblock(sess, fr->conn, offset, len, NULL,
- AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
- return 1;
- }
- /* uncomment this when you're convinced it's right. remember, it's been wrong before.
- if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
- char *buf;
- int i = 8;
- if (modname)
- i += strlen(modname);
- buf = g_malloc(i);
- i = 0;
- if (modname) {
- memcpy(buf, modname, strlen(modname));
- i += strlen(modname);
- }
- buf[i++] = offset & 0xff;
- buf[i++] = (offset >> 8) & 0xff;
- buf[i++] = (offset >> 16) & 0xff;
- buf[i++] = (offset >> 24) & 0xff;
- buf[i++] = len & 0xff;
- buf[i++] = (len >> 8) & 0xff;
- buf[i++] = (len >> 16) & 0xff;
- buf[i++] = (len >> 24) & 0xff;
- aim_sendmemblock(sess, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
- g_free(buf);
- return 1;
- }
- */
-
- pos = g_new0(struct pieceofcrap, 1);
- pos->ic = sess->aux_data;
- pos->conn = fr->conn;
-
- pos->offset = offset;
- pos->len = len;
- pos->modname = modname ? g_strdup(modname) : NULL;
-
- fd = proxy_connect("gaim.sourceforge.net", 80, straight_to_hell, pos);
- if (fd < 0) {
- if (pos->modname)
- g_free(pos->modname);
- g_free(pos);
- imcb_error(sess->aux_data, "Gaim was unable to get a valid hash for logging into AIM."
- " You may be disconnected shortly.");
- }
- pos->fd = fd;
-
- return 1;
-}
-
static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) {
#if 0
struct client_info_s info = {"gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b};
@@ -1165,16 +1029,21 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_
*exch = args->info.chat.roominfo.exchange;
m = g_list_append(m, exch);
- g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg );
+ g_snprintf(txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg);
inv->ic = ic;
inv->exchange = *exch;
inv->name = g_strdup(name);
- imcb_ask( ic, txt, inv, oscar_accept_chat, oscar_reject_chat);
+ imcb_ask(ic, txt, inv, oscar_accept_chat, oscar_reject_chat);
if (name)
g_free(name);
+ } else if (args->reqclass & AIM_CAPS_ICQRTF) {
+ // TODO: constify
+ char text[strlen(args->info.rtfmsg.rtfmsg)+1];
+ strncpy(text, args->info.rtfmsg.rtfmsg, sizeof(text));
+ imcb_buddy_msg(ic, normalize(userinfo->sn), text, 0, 0);
}
return 1;
@@ -2650,7 +2519,8 @@ struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)
static int chat_id = 0;
char * chatname;
- chatname = g_strdup_printf("%s%d", ic->acc->user, chat_id++);
+ chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
+ ic->acc->user, chat_id++);
ret = oscar_chat_join(ic, chatname, NULL, NULL);
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index 2f07adbb..a5fc68ab 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -26,6 +26,7 @@
#include "twitter.h"
#include "twitter_http.h"
#include "twitter_lib.h"
+#include "url.h"
/**
* Main loop function
@@ -69,7 +70,7 @@ static const struct oauth_service twitter_oauth =
{
"http://api.twitter.com/oauth/request_token",
"http://api.twitter.com/oauth/access_token",
- "http://api.twitter.com/oauth/authorize",
+ "https://api.twitter.com/oauth/authorize",
.consumer_key = "xsDNKJuNZYkZyMcu914uEA",
.consumer_secret = "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo",
};
@@ -159,6 +160,9 @@ static void twitter_init( account_t *acc )
{
set_t *s;
+ s = set_add( &acc->set, "base_url", TWITTER_API_URL, NULL, acc );
+ s->flags |= ACC_SET_OFFLINE_ONLY;
+
s = set_add( &acc->set, "message_length", "140", set_eval_int, acc );
s = set_add( &acc->set, "mode", "one", set_eval_mode, acc );
@@ -174,25 +178,39 @@ static void twitter_init( account_t *acc )
static void twitter_login( account_t *acc )
{
struct im_connection *ic = imcb_new( acc );
- struct twitter_data *td = g_new0( struct twitter_data, 1 );
+ struct twitter_data *td;
char name[strlen(acc->user)+9];
+ url_t url;
+ if( !url_set( &url, set_getstr( &ic->acc->set, "base_url" ) ) ||
+ ( url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS ) )
+ {
+ imcb_error( ic, "Incorrect API base URL: %s", set_getstr( &ic->acc->set, "base_url" ) );
+ imc_logout( ic, FALSE );
+ return;
+ }
+
twitter_connections = g_slist_append( twitter_connections, ic );
+ td = g_new0( struct twitter_data, 1 );
ic->proto_data = td;
- ic->flags |= OPT_DOES_HTML;
+
+ td->url_ssl = url.proto == PROTO_HTTPS;
+ td->url_port = url.port;
+ td->url_host = g_strdup( url.host );
+ if( strcmp( url.file, "/" ) != 0 )
+ td->url_path = g_strdup( url.file );
+ else
+ td->url_path = g_strdup( "" );
td->user = acc->user;
- if( !set_getbool( &acc->set, "oauth" ) )
- td->pass = g_strdup( acc->pass );
- else if( strstr( acc->pass, "oauth_token=" ) )
+ if( strstr( acc->pass, "oauth_token=" ) )
td->oauth_info = oauth_from_string( acc->pass, &twitter_oauth );
- td->home_timeline_id = 0;
sprintf( name, "twitter_%s", acc->user );
imcb_add_buddy( ic, name, NULL );
imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
- if( td->pass || td->oauth_info )
+ if( td->oauth_info || !set_getbool( &acc->set, "oauth" ) )
twitter_main_loop_start( ic );
else
twitter_oauth_start( ic );
diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h
index 24f61e42..614919f9 100644
--- a/protocols/twitter/twitter.h
+++ b/protocols/twitter/twitter.h
@@ -41,6 +41,11 @@ struct twitter_data
gint main_loop_id;
struct groupchat *home_timeline_gc;
gint http_fails;
+
+ gboolean url_ssl;
+ int url_port;
+ char *url_host;
+ char *url_path;
};
/**
diff --git a/protocols/twitter/twitter_http.c b/protocols/twitter/twitter_http.c
index 51f437df..ff17f5f4 100644
--- a/protocols/twitter/twitter_http.c
+++ b/protocols/twitter/twitter_http.c
@@ -40,45 +40,21 @@
#include "twitter_http.h"
-char *twitter_url_append(char *url, char *key, char* value);
+static char *twitter_url_append(char *url, char *key, char* value);
/**
* Do a request.
* This is actually pretty generic function... Perhaps it should move to the lib/http_client.c
*/
-void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, char* user, char* pass, struct oauth_info* oi, char** arguments, int arguments_len)
+void *twitter_http(struct im_connection *ic, char *url_string, http_input_function func, gpointer data, int is_post, char** arguments, int arguments_len)
{
- url_t *url = g_new0( url_t, 1 );
+ struct twitter_data *td = ic->proto_data;
char *tmp;
- char *request;
+ GString *request = g_string_new("");
void *ret;
- char *userpass = NULL;
- char *userpass_base64;
char *url_arguments;
- // Fill the url structure.
- if( !url_set( url, url_string ) )
- {
- g_free( url );
- return NULL;
- }
-
- if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS )
- {
- g_free( url );
- return NULL;
- }
-
- // Concatenate user and pass
- if (user && pass) {
- userpass = g_strdup_printf("%s:%s", user, pass);
- userpass_base64 = base64_encode((unsigned char*)userpass, strlen(userpass));
- } else {
- userpass_base64 = NULL;
- }
-
- url_arguments = g_malloc(1);
- url_arguments[0] = '\0';
+ url_arguments = g_strdup("");
// Construct the url arguments.
if (arguments_len != 0)
@@ -92,70 +68,61 @@ void *twitter_http(char *url_string, http_input_function func, gpointer data, in
}
}
- // Do GET stuff...
- if (!is_post)
- {
- // Find the char-pointer of the end of the string.
- tmp = url->file + strlen(url->file);
- tmp[0] = '?';
- // append the url_arguments to the end of the url->file.
- // TODO GM: Check the length?
- g_stpcpy (tmp+1, url_arguments);
- }
-
-
// Make the request.
- request = g_strdup_printf( "%s %s HTTP/1.0\r\n"
- "Host: %s\r\n"
- "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
- is_post ? "POST" : "GET", url->file, url->host );
+ g_string_printf(request, "%s %s%s%s%s HTTP/1.0\r\n"
+ "Host: %s\r\n"
+ "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
+ is_post ? "POST" : "GET",
+ td->url_path, url_string,
+ is_post ? "" : "?", is_post ? "" : url_arguments,
+ td->url_host);
// If a pass and user are given we append them to the request.
- if (oi)
+ if (td->oauth_info)
{
char *full_header;
+ char *full_url;
- full_header = oauth_http_header(oi, is_post ? "POST" : "GET",
- url_string, url_arguments);
+ full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url" ), url_string, NULL);
+ full_header = oauth_http_header(td->oauth_info, is_post ? "POST" : "GET",
+ full_url, url_arguments);
- tmp = g_strdup_printf("%sAuthorization: %s\r\n", request, full_header);
- g_free(request);
+ g_string_append_printf(request, "Authorization: %s\r\n", full_header);
g_free(full_header);
- request = tmp;
+ g_free(full_url);
}
- else if (userpass_base64)
+ else
{
- tmp = g_strdup_printf("%sAuthorization: Basic %s\r\n", request, userpass_base64);
- g_free(request);
- request = tmp;
+ char userpass[strlen(ic->acc->user)+2+strlen(ic->acc->pass)];
+ char *userpass_base64;
+
+ g_snprintf(userpass, sizeof(userpass), "%s:%s", ic->acc->user, ic->acc->pass);
+ userpass_base64 = base64_encode((unsigned char*)userpass, strlen(userpass));
+ g_string_append_printf(request, "Authorization: Basic %s\r\n", userpass_base64);
+ g_free( userpass_base64 );
}
// Do POST stuff..
if (is_post)
{
// Append the Content-Type and url-encoded arguments.
- tmp = g_strdup_printf("%sContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %zd\r\n\r\n%s",
- request, strlen(url_arguments), url_arguments);
- g_free(request);
- request = tmp;
+ g_string_append_printf(request,
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: %zd\r\n\r\n%s",
+ strlen(url_arguments), url_arguments);
} else {
// Append an extra \r\n to end the request...
- tmp = g_strdup_printf("%s\r\n", request);
- g_free(request);
- request = tmp;
+ g_string_append(request, "\r\n");
}
- ret = http_dorequest( url->host, url->port, url->proto == PROTO_HTTPS, request, func, data );
+ ret = http_dorequest(td->url_host, td->url_port, td->url_ssl, request->str, func, data);
- g_free( url );
- g_free( userpass );
- g_free( userpass_base64 );
g_free( url_arguments );
- g_free( request );
+ g_string_free( request, TRUE );
return ret;
}
-char *twitter_url_append(char *url, char *key, char* value)
+static char *twitter_url_append(char *url, char *key, char* value)
{
char *key_encoded = g_strndup(key, 3 * strlen(key));
http_encode(key_encoded);
diff --git a/protocols/twitter/twitter_http.h b/protocols/twitter/twitter_http.h
index 5ef2530f..393a1c26 100644
--- a/protocols/twitter/twitter_http.h
+++ b/protocols/twitter/twitter_http.h
@@ -29,8 +29,8 @@
struct oauth_info;
-void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post,
- char* user, char* pass, struct oauth_info *oi, char** arguments, int arguments_len);
+void *twitter_http(struct im_connection *ic, char *url_string, http_input_function func,
+ gpointer data, int is_post, char** arguments, int arguments_len);
#endif //_TWITTER_HTTP_H
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index 3ea694e6..585bdd43 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -116,6 +116,37 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *
}
}
+/* Warning: May return a malloc()ed value, which will be free()d on the next
+ call. Only for short-term use. */
+static char *twitter_parse_error(struct http_request *req)
+{
+ static char *ret = NULL;
+ struct xt_parser *xp = NULL;
+ struct xt_node *node;
+
+ g_free(ret);
+ ret = NULL;
+
+ if (req->body_size > 0)
+ {
+ xp = xt_new(NULL, NULL);
+ xt_feed(xp, req->reply_body, req->body_size);
+
+ if ((node = xt_find_node(xp->root, "hash")) &&
+ (node = xt_find_node(node->children, "error")) &&
+ node->text_len > 0)
+ {
+ ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
+ xt_free(xp);
+ return ret;
+ }
+
+ xt_free(xp);
+ }
+
+ return req->status_string;
+}
+
static void twitter_http_get_friends_ids(struct http_request *req);
/**
@@ -123,13 +154,11 @@ static void twitter_http_get_friends_ids(struct http_request *req);
*/
void twitter_get_friends_ids(struct im_connection *ic, int next_cursor)
{
- struct twitter_data *td = ic->proto_data;
-
// Primitive, but hey! It works...
char* args[2];
args[0] = "cursor";
args[1] = g_strdup_printf ("%d", next_cursor);
- twitter_http(TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, td->user, td->pass, td->oauth_info, args, 2);
+ twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2);
g_free(args[1]);
}
@@ -195,7 +224,7 @@ static void twitter_http_get_friends_ids(struct http_request *req)
if (req->status_code != 200) {
// It didn't go well, output the error and return.
if (++td->http_fails >= 5)
- imcb_error(ic, "Could not retrieve friends. HTTP STATUS: %d", req->status_code);
+ imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req));
return;
} else {
@@ -395,7 +424,7 @@ void twitter_get_home_timeline(struct im_connection *ic, int next_cursor)
args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id);
}
- twitter_http(TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, td->user, td->pass, td->oauth_info, args, td->home_timeline_id ? 4 : 2);
+ twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, td->home_timeline_id ? 4 : 2);
g_free(args[1]);
if (td->home_timeline_id) {
@@ -433,6 +462,8 @@ static void twitter_groupchat(struct im_connection *ic, GSList *list)
status = l->data;
twitter_add_buddy(ic, status->user->screen_name, status->user->name);
+ strip_html(status->text);
+
// Say it!
if (g_strcasecmp(td->user, status->user->screen_name) == 0)
imcb_chat_log (gc, "Your Tweet: %s", status->text);
@@ -470,6 +501,7 @@ static void twitter_private_message_chat(struct im_connection *ic, GSList *list)
status = l->data;
+ strip_html( status->text );
if( mode_one )
text = g_strdup_printf( "\002<\002%s\002>\002 %s",
status->user->screen_name, status->text );
@@ -522,7 +554,7 @@ static void twitter_http_get_home_timeline(struct http_request *req)
{
// It didn't go well, output the error and return.
if (++td->http_fails >= 5)
- imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ". HTTP STATUS: %d", req->status_code);
+ imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s", twitter_parse_error(req));
return;
}
@@ -574,7 +606,7 @@ static void twitter_http_get_statuses_friends(struct http_request *req)
if (req->status_code != 200) {
// It didn't go well, output the error and return.
if (++td->http_fails >= 5)
- imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL " HTTP STATUS: %d", req->status_code);
+ imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req));
return;
} else {
@@ -613,13 +645,11 @@ static void twitter_http_get_statuses_friends(struct http_request *req)
*/
void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor)
{
- struct twitter_data *td = ic->proto_data;
-
char* args[2];
args[0] = "cursor";
args[1] = g_strdup_printf ("%d", next_cursor);
- twitter_http(TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, td->user, td->pass, td->oauth_info, args, 2);
+ twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2);
g_free(args[1]);
}
@@ -638,7 +668,7 @@ static void twitter_http_post(struct http_request *req)
// Check if the HTTP request went well.
if (req->status_code != 200) {
// It didn't go well, output the error and return.
- imcb_error(ic, "HTTP Error... STATUS: %d", req->status_code);
+ imcb_error(ic, "HTTP error: %s", twitter_parse_error(req));
return;
}
}
@@ -648,12 +678,10 @@ static void twitter_http_post(struct http_request *req)
*/
void twitter_post_status(struct im_connection *ic, char* msg)
{
- struct twitter_data *td = ic->proto_data;
-
char* args[2];
args[0] = "status";
args[1] = msg;
- twitter_http(TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, td->user, td->pass, td->oauth_info, args, 2);
+ twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, args, 2);
// g_free(args[1]);
}
@@ -663,28 +691,21 @@ void twitter_post_status(struct im_connection *ic, char* msg)
*/
void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
{
- struct twitter_data *td = ic->proto_data;
-
char* args[4];
args[0] = "screen_name";
args[1] = who;
args[2] = "text";
args[3] = msg;
// Use the same callback as for twitter_post_status, since it does basically the same.
- twitter_http(TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, td->user, td->pass, td->oauth_info, args, 4);
+ twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4);
// g_free(args[1]);
// g_free(args[3]);
}
void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create)
{
- struct twitter_data *td = ic->proto_data;
-
char* args[2];
args[0] = "screen_name";
args[1] = who;
- twitter_http(create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, td->user, td->pass, td->oauth_info, args, 2);
-}
-
-
-
+ twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, args, 2);
+} \ No newline at end of file
diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h
index 85ba70fc..65a596cc 100644
--- a/protocols/twitter/twitter_lib.h
+++ b/protocols/twitter/twitter_lib.h
@@ -31,49 +31,49 @@
#define TWITTER_API_URL "http://twitter.com"
/* Status URLs */
-#define TWITTER_STATUS_UPDATE_URL TWITTER_API_URL "/statuses/update.xml"
-#define TWITTER_STATUS_SHOW_URL TWITTER_API_URL "/statuses/show/"
-#define TWITTER_STATUS_DESTROY_URL TWITTER_API_URL "/statuses/destroy/"
+#define TWITTER_STATUS_UPDATE_URL "/statuses/update.xml"
+#define TWITTER_STATUS_SHOW_URL "/statuses/show/"
+#define TWITTER_STATUS_DESTROY_URL "/statuses/destroy/"
/* Timeline URLs */
-#define TWITTER_PUBLIC_TIMELINE_URL TWITTER_API_URL "/statuses/public_timeline.xml"
-#define TWITTER_FEATURED_USERS_URL TWITTER_API_URL "/statuses/featured.xml"
-#define TWITTER_FRIENDS_TIMELINE_URL TWITTER_API_URL "/statuses/friends_timeline.xml"
-#define TWITTER_HOME_TIMELINE_URL TWITTER_API_URL "/statuses/home_timeline.xml"
-#define TWITTER_MENTIONS_URL TWITTER_API_URL "/statuses/mentions.xml"
-#define TWITTER_USER_TIMELINE_URL TWITTER_API_URL "/statuses/user_timeline.xml"
+#define TWITTER_PUBLIC_TIMELINE_URL "/statuses/public_timeline.xml"
+#define TWITTER_FEATURED_USERS_URL "/statuses/featured.xml"
+#define TWITTER_FRIENDS_TIMELINE_URL "/statuses/friends_timeline.xml"
+#define TWITTER_HOME_TIMELINE_URL "/statuses/home_timeline.xml"
+#define TWITTER_MENTIONS_URL "/statuses/mentions.xml"
+#define TWITTER_USER_TIMELINE_URL "/statuses/user_timeline.xml"
/* Users URLs */
-#define TWITTER_SHOW_USERS_URL TWITTER_API_URL "/users/show.xml"
-#define TWITTER_SHOW_FRIENDS_URL TWITTER_API_URL "/statuses/friends.xml"
-#define TWITTER_SHOW_FOLLOWERS_URL TWITTER_API_URL "/statuses/followers.xml"
+#define TWITTER_SHOW_USERS_URL "/users/show.xml"
+#define TWITTER_SHOW_FRIENDS_URL "/statuses/friends.xml"
+#define TWITTER_SHOW_FOLLOWERS_URL "/statuses/followers.xml"
/* Direct messages URLs */
-#define TWITTER_DIRECT_MESSAGES_URL TWITTER_API_URL "/direct_messages.xml"
-#define TWITTER_DIRECT_MESSAGES_NEW_URL TWITTER_API_URL "/direct_messages/new.xml"
-#define TWITTER_DIRECT_MESSAGES_SENT_URL TWITTER_API_URL "/direct_messages/sent.xml"
-#define TWITTER_DIRECT_MESSAGES_DESTROY_URL TWITTER_API_URL "/direct_messages/destroy/"
+#define TWITTER_DIRECT_MESSAGES_URL "/direct_messages.xml"
+#define TWITTER_DIRECT_MESSAGES_NEW_URL "/direct_messages/new.xml"
+#define TWITTER_DIRECT_MESSAGES_SENT_URL "/direct_messages/sent.xml"
+#define TWITTER_DIRECT_MESSAGES_DESTROY_URL "/direct_messages/destroy/"
/* Friendships URLs */
-#define TWITTER_FRIENDSHIPS_CREATE_URL TWITTER_API_URL "/friendships/create.xml"
-#define TWITTER_FRIENDSHIPS_DESTROY_URL TWITTER_API_URL "/friendships/destroy.xml"
-#define TWITTER_FRIENDSHIPS_SHOW_URL TWITTER_API_URL "/friendships/show.xml"
+#define TWITTER_FRIENDSHIPS_CREATE_URL "/friendships/create.xml"
+#define TWITTER_FRIENDSHIPS_DESTROY_URL "/friendships/destroy.xml"
+#define TWITTER_FRIENDSHIPS_SHOW_URL "/friendships/show.xml"
/* Social graphs URLs */
-#define TWITTER_FRIENDS_IDS_URL TWITTER_API_URL "/friends/ids.xml"
-#define TWITTER_FOLLOWERS_IDS_URL TWITTER_API_URL "/followers/ids.xml"
+#define TWITTER_FRIENDS_IDS_URL "/friends/ids.xml"
+#define TWITTER_FOLLOWERS_IDS_URL "/followers/ids.xml"
/* Account URLs */
-#define TWITTER_ACCOUNT_RATE_LIMIT_URL TWITTER_API_URL "/account/rate_limit_status.xml"
+#define TWITTER_ACCOUNT_RATE_LIMIT_URL "/account/rate_limit_status.xml"
/* Favorites URLs */
-#define TWITTER_FAVORITES_GET_URL TWITTER_API_URL "/favorites.xml"
-#define TWITTER_FAVORITE_CREATE_URL TWITTER_API_URL "/favorites/create/"
-#define TWITTER_FAVORITE_DESTROY_URL TWITTER_API_URL "/favorites/destroy/"
+#define TWITTER_FAVORITES_GET_URL "/favorites.xml"
+#define TWITTER_FAVORITE_CREATE_URL "/favorites/create/"
+#define TWITTER_FAVORITE_DESTROY_URL "/favorites/destroy/"
/* Block URLs */
-#define TWITTER_BLOCKS_CREATE_URL TWITTER_API_URL "/blocks/create/"
-#define TWITTER_BLOCKS_DESTROY_URL TWITTER_API_URL "/blocks/destroy/"
+#define TWITTER_BLOCKS_CREATE_URL "/blocks/create/"
+#define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/"
void twitter_get_friends_ids(struct im_connection *ic, int next_cursor);
void twitter_get_home_timeline(struct im_connection *ic, int next_cursor);
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index b61f6ff9..e4d541d5 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -137,10 +137,15 @@ static void byahoo_login( account_t *acc )
{
struct im_connection *ic = imcb_new( acc );
struct byahoo_data *yd = ic->proto_data = g_new0( struct byahoo_data, 1 );
+ char *s;
yd->logged_in = FALSE;
yd->current_status = YAHOO_STATUS_AVAILABLE;
+ if( ( s = strchr( acc->user, '@' ) ) && g_strcasecmp( s, "@yahoo.com" ) == 0 )
+ imcb_error( ic, "Your Yahoo! username should just be a username. "
+ "Do not include any @domain part." );
+
imcb_log( ic, "Connecting" );
yd->y2_id = yahoo_init( acc->user, acc->pass );
yahoo_login( yd->y2_id, yd->current_status );
@@ -827,6 +832,10 @@ void ext_yahoo_got_conf_invite( int id, const char *ignored,
char txt[1024];
YList *m;
+ if( g_strcasecmp( who, ic->acc->user ) == 0 )
+ /* WTF, Yahoo! seems to echo these now? */
+ return;
+
inv = g_malloc( sizeof( struct byahoo_conf_invitation ) );
memset( inv, 0, sizeof( struct byahoo_conf_invitation ) );
inv->name = g_strdup( room );