diff options
Diffstat (limited to 'chat-irc/bitlbee/all.patch')
-rw-r--r-- | chat-irc/bitlbee/all.patch | 1231 |
1 files changed, 1231 insertions, 0 deletions
diff --git a/chat-irc/bitlbee/all.patch b/chat-irc/bitlbee/all.patch new file mode 100644 index 0000000000..c844eb58b0 --- /dev/null +++ b/chat-irc/bitlbee/all.patch @@ -0,0 +1,1231 @@ +diff -Bur bitlbee-0.92/bitlbee.c bitlbee-all/bitlbee.c +--- bitlbee-0.92/bitlbee.c 2005-02-23 10:48:31.000000000 -0500 ++++ bitlbee-all/bitlbee.c 2005-04-16 18:08:48.000000000 -0400 +@@ -262,7 +262,7 @@ + { + fgetc( fp ); + line = deobfucrypt( irc, s ); +- root_command_string( irc, ru, line ); ++ root_command_string( irc, ru, line, 0 ); + g_free( line ); + } + fclose( fp ); +@@ -280,7 +280,7 @@ + if( set_getint( irc, "auto_connect" ) ) + { + strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */ +- root_command_string( irc, ru, s ); ++ root_command_string( irc, ru, s, 0 ); + } + + return( 1 ); +@@ -451,7 +451,7 @@ + g_main_quit( global.loop ); + } + +-int root_command_string( irc_t *irc, user_t *u, char *command ) ++int root_command_string( irc_t *irc, user_t *u, char *command, int flags ) + { + char *cmd[IRC_MAX_ARGS]; + char *s; +diff -Bur bitlbee-0.92/bitlbee.h bitlbee-all/bitlbee.h +--- bitlbee-0.92/bitlbee.h 2005-02-23 17:26:59.000000000 -0500 ++++ bitlbee-all/bitlbee.h 2005-04-16 18:00:20.000000000 -0400 +@@ -119,7 +119,7 @@ + gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condition, gpointer data ); + gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condition, gpointer data ); + +-int root_command_string( irc_t *irc, user_t *u, char *command ); ++int root_command_string( irc_t *irc, user_t *u, char *command, int flags ); + int root_command( irc_t *irc, char *command[] ); + int bitlbee_load( irc_t *irc, char *password ); + int bitlbee_save( irc_t *irc ); +diff -Bur bitlbee-0.92/commands.c bitlbee-all/commands.c +--- bitlbee-0.92/commands.c 2005-02-08 16:48:35.000000000 -0500 ++++ bitlbee-all/commands.c 2005-04-16 18:04:27.000000000 -0400 +@@ -128,7 +128,7 @@ + if( checkie == -2 ) + { + setpassnc( irc, cmd[1] ); +- root_command_string( irc, user_find( irc, irc->mynick ), "save" ); ++ root_command_string( irc, user_find( irc, irc->mynick ), "save", 0 ); + irc->status = USTATUS_IDENTIFIED; + } + else +diff -Bur bitlbee-0.92/irc.c bitlbee-all/irc.c +--- bitlbee-0.92/irc.c 2005-02-23 18:32:02.000000000 -0500 ++++ bitlbee-all/irc.c 2005-05-23 18:56:42.000000000 -0400 +@@ -576,7 +576,7 @@ + else + irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); + } +- else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 ) ++ else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) + { + if( !( cmd[1] && cmd[2] ) ) + { +@@ -620,7 +620,7 @@ + { + irc->is_private = 1; + } +- irc_send( irc, cmd[1], cmd[2] ); ++ irc_send( irc, cmd[1], cmd[2], (g_strcasecmp( cmd[0], "NOTICE") == 0) ? IM_FLAG_AWAY : 0 ); + } + } + else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 ) +@@ -1289,7 +1289,7 @@ + irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel ); + } + +-int irc_send( irc_t *irc, char *nick, char *s ) ++int irc_send( irc_t *irc, char *nick, char *s, int flags ) + { + struct conversation *c = NULL; + user_t *u = NULL; +@@ -1377,7 +1377,7 @@ + } + + if( u->send_handler ) +- return( u->send_handler( irc, u, s ) ); ++ return( u->send_handler( irc, u, s, flags ) ); + } + else if( c && c->gc && c->gc->prpl ) + { +@@ -1392,7 +1392,7 @@ + user_t *u = data; + + u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */ +- serv_send_im( u->gc->irc, u, u->sendbuf ); ++ serv_send_im( u->gc->irc, u, u->sendbuf, 0 ); + + g_free( u->sendbuf ); + u->sendbuf = NULL; +@@ -1402,7 +1402,7 @@ + return( FALSE ); + } + +-int buddy_send_handler( irc_t *irc, user_t *u, char *msg ) ++int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) + { + if( !u || !u->gc ) return( 0 ); + +@@ -1432,7 +1432,7 @@ + } + else + { +- return( serv_send_im( irc, u, msg ) ); ++ return( serv_send_im( irc, u, msg, flags ) ); + } + } + +diff -Bur bitlbee-0.92/irc.h bitlbee-all/irc.h +--- bitlbee-0.92/irc.h 2005-02-08 15:58:30.000000000 -0500 ++++ bitlbee-all/irc.h 2005-04-16 17:58:09.000000000 -0400 +@@ -137,11 +137,11 @@ + void irc_whois( irc_t *irc, char *nick ); + int irc_away( irc_t *irc, char *away ); + +-int irc_send( irc_t *irc, char *nick, char *s ); ++int irc_send( irc_t *irc, char *nick, char *s, int flags ); + int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg ); + int irc_msgfrom( irc_t *irc, char *nick, char *msg ); + int irc_noticefrom( irc_t *irc, char *nick, char *msg ); + +-int buddy_send_handler( irc_t *irc, user_t *u, char *msg ); ++int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ); + + #endif +diff -Bur bitlbee-0.92/protocols/nogaim.c bitlbee-all/protocols/nogaim.c +--- bitlbee-0.92/protocols/nogaim.c 2005-02-23 10:47:58.000000000 -0500 ++++ bitlbee-all/protocols/nogaim.c 2005-05-15 22:51:55.000000000 -0400 +@@ -167,7 +167,7 @@ + should be a compare function inside the PRPL module, but I do it this + way for now because I don't want to touch the Gaim code too much since + it's not going to be here for too long anymore. */ +-int handle_cmp( char *a, char *b, int protocol ) ++int handle_cmp( const char *a, const char *b, int protocol ) + { + if( protocol == PROTO_TOC || protocol == PROTO_ICQ ) + { +@@ -283,6 +283,9 @@ + msg = buf; + else + msg = text; ++ ++ if( g_strcasecmp( set_getstr(gc->irc, "html" ), "strip" ) == 0 ) ++ strip_html( msg ); + + irc_usermsg( gc->irc, "%s - %s", proto_name[gc->protocol], msg ); + } +@@ -596,6 +599,11 @@ + for( c = gc->conversations; c; c = c->next ) + remove_chat_buddy_silent( c, handle ); + } ++ ++ if( ( type & UC_UNAVAILABLE ) && ( gc->prpl->get_away ) ) ++ { ++ // gc->prpl->get_away( gc, handle ); ++ } + + if( ( type & UC_UNAVAILABLE ) && ( gc->protocol == PROTO_OSCAR || gc->protocol == PROTO_TOC ) ) + { +@@ -628,6 +636,20 @@ + } + } + ++void serv_got_away( struct gaim_connection *gc, char *handle, char *away) ++{ ++ user_t *u; ++ ++ u = user_findhandle( gc, handle ); ++ if(!u || !away) return; ++ if(u->away) ++ g_free(u->away); ++ ++ u->away = g_strdup(away); ++ if( g_strcasecmp( set_getstr( gc->irc, "html" ), "strip" ) == 0 ) ++ strip_html(u->away); ++} ++ + void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ) + { + irc_t *irc = gc->irc; +@@ -829,7 +851,7 @@ + irc_usermsg( b->gc->irc, "User %s added to conversation %d", handle, b->id ); + + /* It might be yourself! */ +- if( g_strcasecmp( handle, b->gc->user->username ) == 0 ) ++ if( handle_cmp( handle, b->gc->user->username, b->gc->protocol ) == 0 ) + { + u = user_find( b->gc->irc, b->gc->irc->nick ); + if( !b->joined ) +@@ -993,15 +1015,21 @@ + return( set_eval_bool( irc, set, value ) ); + } + +-int serv_send_im( irc_t *irc, user_t *u, char *msg ) ++int serv_send_im( irc_t *irc, user_t *u, char *msg, int flags ) + { + char buf[8192]; + + if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && + do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 ) + msg = buf; ++ ++ if( u->gc->flags & OPT_CONN_HTML) { ++ char * html = escape_html(msg); ++ strncpy(buf, html, 8192); ++ g_free(html); ++ } + +- return( ((struct gaim_connection *)u->gc)->prpl->send_im( u->gc, u->handle, msg, strlen( msg ), 0 ) ); ++ return( ((struct gaim_connection *)u->gc)->prpl->send_im( u->gc, u->handle, msg, strlen( msg ), flags ) ); + } + + int serv_send_chat( irc_t *irc, struct gaim_connection *gc, int id, char *msg ) +@@ -1011,6 +1039,12 @@ + if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && + do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 ) + msg = buf; ++ ++ if( gc->flags & OPT_CONN_HTML) { ++ char * html = escape_html(msg); ++ strncpy(buf, html, 8192); ++ g_free(html); ++ } + + return( gc->prpl->chat_send( gc, id, msg ) ); + } +diff -Bur bitlbee-0.92/protocols/nogaim.h bitlbee-all/protocols/nogaim.h +--- bitlbee-0.92/protocols/nogaim.h 2004-10-29 19:42:07.000000000 -0400 ++++ bitlbee-all/protocols/nogaim.h 2005-05-15 20:19:20.000000000 -0400 +@@ -249,7 +249,7 @@ + extern struct prpl *proto_prpl[16]; + + /* nogaim.c */ +-int serv_send_im(irc_t *irc, user_t *u, char *msg); ++int serv_send_im(irc_t *irc, user_t *u, char *msg, int flags); + int serv_send_chat(irc_t *irc, struct gaim_connection *gc, int id, char *msg ); + + G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); +@@ -258,7 +258,7 @@ + void nogaim_init(); + int proto_away( struct gaim_connection *gc, char *away ); + char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ); +-int handle_cmp( char *a, char *b, int protocol ); ++int handle_cmp(const char *a,const char *b, int protocol ); + + gboolean auto_reconnect( gpointer data ); + void cancel_auto_reconnect( struct account *a ); +@@ -297,6 +297,7 @@ + + /* server.c */ + G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ); ++G_MODULE_EXPORT void serv_got_away( struct gaim_connection *gc, char *handle, char *away); + G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ); + G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout ); + G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data ); +@@ -314,6 +315,7 @@ + G_MODULE_EXPORT char *normalize( const char *s ); + G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); + G_MODULE_EXPORT void strip_html( char *msg ); ++G_MODULE_EXPORT char * escape_html(const char *html); + G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value); + + #ifdef WITH_MSN +diff -Bur bitlbee-0.92/protocols/oscar/aim.h bitlbee-all/protocols/oscar/aim.h +--- bitlbee-0.92/protocols/oscar/aim.h 2004-10-10 07:24:06.000000000 -0400 ++++ bitlbee-all/protocols/oscar/aim.h 2005-05-23 21:57:53.000000000 -0400 +@@ -439,6 +439,7 @@ + int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v); + int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps); + int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 type); ++int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance); + int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *ui); + int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl); + int aim_counttlvchain(aim_tlvlist_t **list); +@@ -633,6 +634,12 @@ + unsigned short instance; + }; + ++struct aim_chat_invitation { ++ struct gaim_connection * gc; ++ char * name; ++ guint8 exchange; ++}; ++ + #define AIM_IMFLAGS_AWAY 0x0001 /* mark as an autoreply */ + #define AIM_IMFLAGS_ACK 0x0002 /* request a receipt notice */ + #define AIM_IMFLAGS_UNICODE 0x0004 +@@ -811,6 +818,9 @@ + aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const guint8 *cookie); + + int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type); ++int aim_send_im_ch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, unsigned short exchange, const char *roomname, unsigned short instance); ++int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2); ++ + aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, guint16 numfiles, guint32 totsize); + + aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn); +diff -Bur bitlbee-0.92/protocols/oscar/aim_cbtypes.h bitlbee-all/protocols/oscar/aim_cbtypes.h +--- bitlbee-0.92/protocols/oscar/aim_cbtypes.h 2004-07-14 08:28:33.000000000 -0400 ++++ bitlbee-all/protocols/oscar/aim_cbtypes.h 2005-04-05 21:35:58.000000000 -0400 +@@ -99,6 +99,7 @@ + #define AIM_CB_MSG_MISSEDCALL 0x000a + #define AIM_CB_MSG_CLIENTAUTORESP 0x000b + #define AIM_CB_MSG_ACK 0x000c ++#define AIM_CB_MSG_MTN 0x0014 + #define AIM_CB_MSG_DEFAULT 0xffff + + /* +diff -Bur bitlbee-0.92/protocols/oscar/chat.c bitlbee-all/protocols/oscar/chat.c +--- bitlbee-0.92/protocols/oscar/chat.c 2004-10-10 07:24:06.000000000 -0400 ++++ bitlbee-all/protocols/oscar/chat.c 2005-03-26 16:47:45.000000000 -0500 +@@ -182,31 +182,6 @@ + return 0; + } + +-static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) +-{ +- guint8 *buf; +- int buflen; +- aim_bstream_t bs; +- +- buflen = 2 + 1 + strlen(roomname) + 2; +- +- if (!(buf = g_malloc(buflen))) +- return 0; +- +- aim_bstream_init(&bs, buf, buflen); +- +- aimbs_put16(&bs, exchange); +- aimbs_put8(&bs, strlen(roomname)); +- aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname)); +- aimbs_put16(&bs, instance); +- +- aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); +- +- g_free(buf); +- +- return 0; +-} +- + /* + * Join a room of name roomname. This is the first step to joining an + * already created room. It's basically a Service Request for +diff -Bur bitlbee-0.92/protocols/oscar/im.c bitlbee-all/protocols/oscar/im.c +--- bitlbee-0.92/protocols/oscar/im.c 2004-10-10 07:24:06.000000000 -0400 ++++ bitlbee-all/protocols/oscar/im.c 2005-05-23 21:55:50.000000000 -0400 +@@ -365,6 +365,94 @@ + } + + /* ++ * Subtype 0x0006 - Send a chat invitation. ++ */ ++int aim_send_im_ch2_chatinvite(aim_session_t *sess, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance) ++{ ++ aim_conn_t *conn; ++ aim_frame_t *fr; ++ aim_snacid_t snacid; ++ int i; ++ aim_msgcookie_t *cookie; ++ struct aim_invite_priv *priv; ++ guint8 ck[8]; ++ aim_tlvlist_t *otl = NULL, *itl = NULL; ++ guint8 *hdr; ++ int hdrlen; ++ aim_bstream_t hdrbs; ++ ++ if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) ++ return -EINVAL; ++ ++ if (!sn || !msg || !roomname) ++ return -EINVAL; ++ ++ for (i = 0; i < 8; i++) ++ ck[i] = (guint8)rand(); ++ ++ if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) ++ return -ENOMEM; ++ ++ snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); ++ aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); ++ ++ /* XXX should be uncached by an unwritten 'invite accept' handler */ ++ if ((priv = g_malloc(sizeof(struct aim_invite_priv)))) { ++ priv->sn = g_strdup(sn); ++ priv->roomname = g_strdup(roomname); ++ priv->exchange = exchange; ++ priv->instance = instance; ++ } ++ ++ if ((cookie = aim_mkcookie(ck, AIM_COOKIETYPE_INVITE, priv))) ++ aim_cachecookie(sess, cookie); ++ else ++ g_free(priv); ++ ++ /* ICBM Header */ ++ aimbs_putraw(&fr->data, ck, 8); /* Cookie */ ++ aimbs_put16(&fr->data, 0x0002); /* Channel */ ++ aimbs_put8(&fr->data, strlen(sn)); /* Screename length */ ++ aimbs_putraw(&fr->data, sn, strlen(sn)); /* Screenname */ ++ ++ /* ++ * TLV t(0005) ++ * ++ * Everything else is inside this TLV. ++ * ++ * Sigh. AOL was rather inconsistent right here. So we have ++ * to play some minor tricks. Right inside the type 5 is some ++ * raw data, followed by a series of TLVs. ++ * ++ */ ++ hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; ++ hdr = g_malloc(hdrlen); ++ aim_bstream_init(&hdrbs, hdr, hdrlen); ++ ++ aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ ++ aimbs_putraw(&hdrbs, ck, sizeof(ck)); /* I think... */ ++ aim_putcap(&hdrbs, AIM_CAPS_CHAT); ++ ++ aim_addtlvtochain16(&itl, 0x000a, 0x0001); ++ aim_addtlvtochain_noval(&itl, 0x000f); ++ aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); ++ aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); ++ aim_writetlvchain(&hdrbs, &itl); ++ ++ aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); ++ ++ aim_writetlvchain(&fr->data, &otl); ++ ++ g_free(hdr); ++ aim_freetlvchain(&itl); ++ aim_freetlvchain(&otl); ++ ++ aim_tx_enqueue(sess, fr); ++ ++ return 0; ++} ++ ++/* + * This is also performance sensitive. (If you can believe it...) + * + */ +@@ -1987,6 +2075,90 @@ + return ret; + } + ++/* ++ * Subtype 0x0014 - Send a mini typing notification (mtn) packet. ++ * ++ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, ++ * and Gaim 0.60 and newer. ++ * ++ */ ++int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2) ++{ ++ aim_conn_t *conn; ++ aim_frame_t *fr; ++ aim_snacid_t snacid; ++ ++ if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002))) ++ return -EINVAL; ++ ++ if (!sn) ++ return -EINVAL; ++ ++ if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2))) ++ return -ENOMEM; ++ ++ snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0); ++ aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid); ++ ++ /* ++ * 8 days of light ++ * Er, that is to say, 8 bytes of 0's ++ */ ++ aimbs_put16(&fr->data, 0x0000); ++ aimbs_put16(&fr->data, 0x0000); ++ aimbs_put16(&fr->data, 0x0000); ++ aimbs_put16(&fr->data, 0x0000); ++ ++ /* ++ * Type 1 (should be 0x0001 for mtn) ++ */ ++ aimbs_put16(&fr->data, type1); ++ ++ /* ++ * Dest sn ++ */ ++ aimbs_put8(&fr->data, strlen(sn)); ++ aimbs_putraw(&fr->data, sn, strlen(sn)); ++ ++ /* ++ * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn) ++ */ ++ aimbs_put16(&fr->data, type2); ++ ++ aim_tx_enqueue(sess, fr); ++ ++ return 0; ++} ++ ++/* ++ * Subtype 0x0014 - Receive a mini typing notification (mtn) packet. ++ * ++ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, ++ * and Gaim 0.60 and newer. ++ * ++ */ ++static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) ++{ ++ int ret = 0; ++ aim_rxcallback_t userfunc; ++ char *sn; ++ guint8 snlen; ++ guint16 type1, type2; ++ ++ aim_bstream_advance(bs, 8); /* Unknown - All 0's */ ++ type1 = aimbs_get16(bs); ++ snlen = aimbs_get8(bs); ++ sn = aimbs_getstr(bs, snlen); ++ type2 = aimbs_get16(bs); ++ ++ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ++ ret = userfunc(sess, rx, type1, sn, type2); ++ ++ g_free(sn); ++ ++ return ret; ++} ++ + static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) + { + +@@ -2002,6 +2174,8 @@ + return clientautoresp(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x000c) + return msgack(sess, mod, rx, snac, bs); ++ else if (snac->subtype == 0x0014) ++ return mtn_receive(sess, mod, rx, snac, bs); + + return 0; + } +diff -Bur bitlbee-0.92/protocols/oscar/info.c bitlbee-all/protocols/oscar/info.c +--- bitlbee-0.92/protocols/oscar/info.c 2004-10-10 07:24:06.000000000 -0400 ++++ bitlbee-all/protocols/oscar/info.c 2005-03-29 19:19:41.000000000 -0500 +@@ -614,8 +614,10 @@ + { + aim_userinfo_t userinfo; + char *text_encoding = NULL, *text = NULL; ++ guint16 text_length = 0; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; ++ aim_tlv_t *tlv; + aim_snac_t *origsnac = NULL; + struct aim_priv_inforeq *inforeq; + int ret = 0; +@@ -649,10 +651,18 @@ + */ + if (inforeq->infotype == AIM_GETINFO_GENERALINFO) { + text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); +- text = aim_gettlv_str(tlvlist, 0x0002, 1); ++ if((tlv = aim_gettlv(tlvlist, 0x0002, 1))) { ++ text = g_new0(char, tlv->length); ++ memcpy(text, tlv->value, tlv->length); ++ text_length = tlv->length; ++ } + } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) { + text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); +- text = aim_gettlv_str(tlvlist, 0x0004, 1); ++ if((tlv = aim_gettlv(tlvlist, 0x0004, 1))) { ++ text = g_new0(char, tlv->length); ++ memcpy(text, tlv->value, tlv->length); ++ text_length = tlv->length; ++ } + } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) { + aim_tlv_t *ct; + +@@ -667,7 +677,7 @@ + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) +- ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text); ++ ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, text_length); + + g_free(text_encoding); + g_free(text); +diff -Bur bitlbee-0.92/protocols/oscar/oscar.c bitlbee-all/protocols/oscar/oscar.c +--- bitlbee-0.92/protocols/oscar/oscar.c 2005-02-23 17:26:59.000000000 -0500 ++++ bitlbee-all/protocols/oscar/oscar.c 2005-05-24 22:33:02.000000000 -0400 +@@ -54,7 +54,7 @@ + /* Don't know if support for UTF8 is really working. For now it's UTF16 here. + static int gaim_caps = AIM_CAPS_UTF8; */ + +-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT; ++static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_CHAT; + static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02}; + + struct oscar_data { +@@ -82,6 +82,8 @@ + gboolean icq; + GSList *evilhack; + ++ GSList *info_requests; /*Used to separate away message requests the user made from automatic ones*/ ++ + struct { + guint maxbuddies; /* max users you can watch */ + guint maxwatchers; /* max users who can watch you */ +@@ -148,7 +150,6 @@ + return tmp; + } + +-#if 0 + static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) { + GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; + struct chat_connection *c = NULL; +@@ -163,7 +164,7 @@ + + return c; + } +-#endif ++ + + static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc, + aim_conn_t *conn) { +@@ -215,6 +216,8 @@ + static int gaim_ssi_parseack (aim_session_t *, aim_frame_t *, ...); + + static int gaim_icqinfo (aim_session_t *, aim_frame_t *, ...); ++static int gaim_parseaiminfo (aim_session_t *, aim_frame_t *, ...); ++static int gaim_parsemtn (aim_session_t *, aim_frame_t *, ...); + + static char *msgerrreason[] = { + "Invalid error", +@@ -422,6 +425,11 @@ + odata->create_rooms = g_slist_remove(odata->create_rooms, cr); + g_free(cr); + } ++ while(odata->info_requests) { ++ char * data = odata->info_requests->data; ++ odata->info_requests = g_slist_remove(odata->info_requests, data); ++ g_free(data); ++ } + if (odata->email) + g_free(odata->email); + if (odata->newp) +@@ -548,6 +556,8 @@ + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0); ++ aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0); ++ aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0); + + ((struct oscar_data *)gc->proto_data)->conn = bosconn; + for (i = 0; i < (int)strlen(info->bosip); i++) { +@@ -1071,33 +1081,6 @@ + return 1; + } + +-static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { +-#if 0 +- struct gaim_connection *gc = sess->aux_data; +-#endif +- +- if (args->status != AIM_RENDEZVOUS_PROPOSE) +- return 1; +-#if 0 +- if (args->reqclass & AIM_CAPS_CHAT) { +- char *name = extract_name(args->info.chat.roominfo.name); +- int *exch = g_new0(int, 1); +- GList *m = NULL; +- m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name)); +- *exch = args->info.chat.roominfo.exchange; +- m = g_list_append(m, exch); +- serv_got_chat_invite(gc, +- name ? name : args->info.chat.roominfo.name, +- userinfo->sn, +- (char *)args->msg, +- m); +- if (name) +- g_free(name); +- } +-#endif +- return 1; +-} +- + static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { + char *uin, message; + struct oscar_data *od = (struct oscar_data *)data->gc->proto_data; +@@ -1201,6 +1184,12 @@ + return 1; + } + ++int handle_cmp_aim(const char * a, const char * b) { ++ return handle_cmp(a, b, PROTO_TOC); ++} ++ ++static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args); ++ + static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) { + int channel, ret = 0; + aim_userinfo_t *userinfo; +@@ -1357,6 +1346,10 @@ + char *destn; + guint16 reason; + char buf[1024]; ++ GSList *l; ++ struct oscar_data *od; ++ ++ od = ((struct gaim_connection*)sess->aux_data)->proto_data; + + va_start(ap, fr); + reason = (guint16)va_arg(ap, unsigned int); +@@ -1367,6 +1360,11 @@ + (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); + do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); + ++ if((l = g_slist_find_custom(od->info_requests, destn, (GCompareFunc)handle_cmp_aim))) { ++ g_free(l->data); ++ od->info_requests = g_slist_remove(od->info_requests, l); ++ } ++ + return 1; + } + +@@ -1663,6 +1661,7 @@ + va_end(ap); + + /* Maybe senderwarn and recverwarn should be user preferences... */ ++ params->flags = 0x0000000b; + params->maxmsglen = 8000; + params->minmsginterval = 0; + +@@ -1869,11 +1868,12 @@ + struct oscar_data *odata = (struct oscar_data *)g->proto_data; + if (odata->icq) + aim_icq_getallinfo(odata->sess, name); +- else +- /* people want the away message on the top, so we get the away message +- * first and then get the regular info, since it's too difficult to +- * insert in the middle. i hate people. */ ++ else { + aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE); ++ aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO); ++ if(!g_slist_find_custom(odata->info_requests, name, (GCompareFunc)handle_cmp_aim)) ++ odata->info_requests = g_slist_append(odata->info_requests, g_strdup(name)); ++ } + } + + static void oscar_get_away(struct gaim_connection *g, char *who) { +@@ -1885,7 +1885,7 @@ + if (budlight->caps & AIM_CAPS_ICQSERVERRELAY) + aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7); + } else +- aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_GENERALINFO); ++ aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE); + } + + static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *message) +@@ -1977,7 +1977,8 @@ + static void oscar_remove_buddy(struct gaim_connection *g, char *name, char *group) { + struct oscar_data *odata = (struct oscar_data *)g->proto_data; + struct aim_ssi_item *ssigroup; +- while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)); ++ while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && ++ !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)); + } + + static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) { +@@ -2286,6 +2287,144 @@ + + } + ++static char *oscar_encoding_extract(const char *encoding) ++{ ++ char *ret = NULL; ++ char *begin, *end; ++ ++ g_return_val_if_fail(encoding != NULL, NULL); ++ ++ /* Make sure encoding begins with charset= */ ++ if (strncmp(encoding, "text/plain; charset=", 20) && ++ strncmp(encoding, "text/aolrtf; charset=", 21) && ++ strncmp(encoding, "text/x-aolrtf; charset=", 23)) ++ { ++ return NULL; ++ } ++ ++ begin = strchr(encoding, '"'); ++ end = strrchr(encoding, '"'); ++ ++ if ((begin == NULL) || (end == NULL) || (begin >= end)) ++ return NULL; ++ ++ ret = g_strndup(begin+1, (end-1) - begin); ++ ++ return ret; ++} ++ ++static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen) ++{ ++ char *utf8 = g_new0(char, 8192); ++ ++ if ((encoding == NULL) || encoding[0] == '\0') { ++ /* gaim_debug_info("oscar", "Empty encoding, assuming UTF-8\n");*/ ++ } else if (!g_strcasecmp(encoding, "iso-8859-1")) { ++ do_iconv("iso-8859-1", "UTF-8", text, utf8, textlen, 8192); ++ } else if (!g_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1")) { ++ do_iconv("Windows-1252", "UTF-8", text, utf8, textlen, 8192); ++ } else if (!g_strcasecmp(encoding, "unicode-2-0")) { ++ do_iconv("UCS-2BE", "UTF-8", text, utf8, textlen, 8192); ++ } else if (g_strcasecmp(encoding, "us-ascii") && strcmp(encoding, "utf-8")) { ++ /* gaim_debug_warning("oscar", "Unrecognized character encoding \"%s\", " ++ "attempting to convert to UTF-8 anyway\n", encoding);*/ ++ do_iconv(encoding, "UTF-8", text, utf8, textlen, 8192); ++ } ++ ++ /* ++ * If utf8 is still NULL then either the encoding is us-ascii/utf-8 or ++ * we have been unable to convert the text to utf-8 from the encoding ++ * that was specified. So we check if the text is valid utf-8 then ++ * just copy it. ++ */ ++ if (*utf8 == 0) { ++ if (textlen != 0 && *text != '\0' ++ && !g_utf8_validate(text, textlen, NULL)) ++ strcpy(utf8, _("(There was an error receiving this message. The buddy you are speaking to most likely has a buggy client.)")); ++ else ++ strncpy(utf8, text, textlen); ++ } ++ ++ return utf8; ++} ++ ++static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...) ++{ ++ struct gaim_connection *gc = sess->aux_data; ++ struct oscar_data *od = gc->proto_data; ++ va_list ap; ++ aim_userinfo_t *userinfo; ++ guint16 infotype; ++ char *text_encoding = NULL, *text = NULL, *extracted_encoding = NULL; ++ guint16 text_length; ++ char *utf8 = NULL; ++ GSList *l; ++ ++ va_start(ap, fr); ++ userinfo = va_arg(ap, aim_userinfo_t *); ++ infotype = va_arg(ap, int); ++ text_encoding = va_arg(ap, char*); ++ text = va_arg(ap, char*); ++ text_length = va_arg(ap, int); ++ va_end(ap); ++ ++ if(text_encoding) ++ extracted_encoding = oscar_encoding_extract(text_encoding); ++ if(infotype == AIM_GETINFO_GENERALINFO) { ++ /*Display idle time*/ ++ char buff[256]; ++ struct tm idletime; ++ if(userinfo->idletime) { ++ memset(&idletime, 0, sizeof(struct tm)); ++ idletime.tm_mday = (userinfo->idletime / 60) / 24; ++ idletime.tm_hour = (userinfo->idletime / 60) % 24; ++ idletime.tm_min = userinfo->idletime % 60; ++ idletime.tm_sec = 0; ++ strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime); ++ serv_got_crap(gc, "%s: %s", _("Idle Time"), buff); ++ } ++ ++ if(text) { ++ utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); ++ serv_got_crap(gc, "%s\n%s", _("User Info"), utf8); ++ } else { ++ serv_got_crap(gc, _("No user info available.")); ++ } ++ } else if(infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) { ++ utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); ++ if((l = g_slist_find_custom(od->info_requests, userinfo->sn, (GCompareFunc)handle_cmp_aim))) { ++ /*If the user requested info, display it, otherwise just pass it on*/ ++ g_free(l->data); ++ od->info_requests = g_slist_remove(od->info_requests, l); ++ serv_got_crap(gc, "%s\n%s", _("Away Message"), utf8); ++ } ++ serv_got_away(gc, userinfo->sn, utf8); ++ } ++ ++ g_free(utf8); ++ ++ return 1; ++} ++ ++int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...) ++{ ++ struct gaim_connection * gc = sess->aux_data; ++ va_list ap; ++ guint16 type1, type2; ++ char * sn; ++ ++ va_start(ap, fr); ++ type1 = va_arg(ap, int); ++ sn = va_arg(ap, char*); ++ type2 = va_arg(ap, int); ++ va_end(ap); ++ ++ if(type2 == 0x0001 || type2 == 0x0002) ++ serv_got_typing(gc, sn, 0); ++ ++ return 1; ++} ++ + static char *oscar_get_status_string( struct gaim_connection *gc, int number ) + { + struct oscar_data *od = gc->proto_data; +@@ -2314,6 +2453,177 @@ + } + } + ++int oscar_chat_send(struct gaim_connection * gc, int id, char *message) ++{ ++ struct oscar_data * od = (struct oscar_data*)gc->proto_data; ++ struct chat_connection * ccon; ++ ++ if(!(ccon = find_oscar_chat(gc, id))) ++ return -1; ++ ++ int ret; ++ guint8 len = strlen(message); ++ char *s; ++ ++ for (s = message; *s; s++) ++ if (*s & 128) ++ break; ++ ++ /* Message contains high ASCII chars, time for some translation! */ ++ if (*s) { ++ s = g_malloc(BUF_LONG); ++ /* Try if we can put it in an ISO8859-1 string first. ++ If we can't, fall back to UTF16. */ ++ if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) { ++ len = ret; ++ } else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) { ++ len = ret; ++ } else { ++ /* OOF, translation failed... Oh well.. */ ++ g_free( s ); ++ s = message; ++ } ++ } else { ++ s = message; ++ } ++ ++ ret = aim_chat_send_im(od->sess, ccon->conn, AIM_CHATFLAGS_NOREFLECT, s, len); ++ ++ if (s != message) { ++ g_free(s); ++ } ++ ++ return (ret >= 0); ++} ++ ++void oscar_chat_invite(struct gaim_connection * gc, int id, char *message, char *who) ++{ ++ struct oscar_data * od = (struct oscar_data *)gc->proto_data; ++ struct chat_connection *ccon = find_oscar_chat(gc, id); ++ ++ if (ccon == NULL) ++ return; ++ ++ aim_send_im_ch2_chatinvite(od->sess, who, message ? message : "", ++ ccon->exchange, ccon->name, 0x0); ++} ++ ++void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc) ++{ ++ struct oscar_data *od = (struct oscar_data *)gc->proto_data; ++ ++ /* Notify the conversation window that we've left the chat */ ++ serv_got_chat_left(gc, cc->id); ++ ++ /* Destroy the chat_connection */ ++ od->oscar_chats = g_slist_remove(od->oscar_chats, cc); ++ if (cc->inpa > 0) ++ gaim_input_remove(cc->inpa); ++ aim_conn_kill(od->sess, &cc->conn); ++ g_free(cc->name); ++ g_free(cc->show); ++ g_free(cc); ++} ++ ++void oscar_chat_leave(struct gaim_connection * gc, int id) ++{ ++ struct chat_connection * ccon = find_oscar_chat(gc, id); ++ ++ if(ccon == NULL) ++ return; ++ ++ oscar_chat_kill(gc, ccon); ++} ++ ++int oscar_chat_join(struct gaim_connection * gc, char * name) ++{ ++ struct oscar_data * od = (struct oscar_data *)gc->proto_data; ++ ++ aim_conn_t * cur; ++ ++ if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) { ++ ++ return (aim_chatnav_createroom(od->sess, cur, name, 4) == 0); ++ ++ } else { ++ struct create_room * cr = g_new0(struct create_room, 1); ++ cr->exchange = 4; ++ cr->name = g_strdup(name); ++ od->create_rooms = g_slist_append(od->create_rooms, cr); ++ aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV); ++ return 1; ++ } ++} ++ ++int oscar_chat_open(struct gaim_connection * gc, char *who) ++{ ++ struct oscar_data * od = (struct oscar_data *)gc->proto_data; ++ ++ static int chat_id = 0; ++ char * chatname = g_new0(char, strlen(gc->username)+4); ++ g_snprintf(chatname, strlen(gc->username) + 4, "%s%d", gc->username, chat_id++); ++ ++ int ret = oscar_chat_join(gc, chatname); ++ ++ aim_send_im_ch2_chatinvite(od->sess, who, "", ++ 4, chatname, 0x0); ++ g_free(chatname); ++ ++ return ret; ++} ++ ++void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv) ++{ ++ oscar_chat_join(inv->gc, inv->name); ++ g_free(inv->name); ++ g_free(inv); ++} ++ ++void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv) ++{ ++ g_free(inv->name); ++ g_free(inv); ++} ++ ++static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { ++ struct gaim_connection *gc = sess->aux_data; ++ ++ if (args->status != AIM_RENDEZVOUS_PROPOSE) ++ return 1; ++ ++ if (args->reqclass & AIM_CAPS_CHAT) { ++ char *name = extract_name(args->info.chat.roominfo.name); ++ int *exch = g_new0(int, 1); ++ GList *m = NULL; ++ m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name)); ++ *exch = args->info.chat.roominfo.exchange; ++ m = g_list_append(m, exch); ++ ++ char txt[1024]; ++ ++ g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg ); ++ ++ struct aim_chat_invitation * inv = g_new0(struct aim_chat_invitation, 1); ++ ++ inv->gc = gc; ++ inv->exchange = *exch; ++ inv->name = g_strdup(name); ++ ++ do_ask_dialog( gc, txt, inv, oscar_accept_chat, oscar_reject_chat); ++ ++ if (name) ++ g_free(name); ++ } ++ ++ return 1; ++} ++ ++int oscar_send_typing(struct gaim_connection *gc, char * who, int typing) ++{ ++ struct oscar_data *od = gc->proto_data; ++ return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) ); ++} ++ + static struct prpl *my_protocol = NULL; + + void oscar_init(struct prpl *ret) { +@@ -2327,6 +2637,10 @@ + ret->get_away = oscar_get_away; + ret->add_buddy = oscar_add_buddy; + ret->remove_buddy = oscar_remove_buddy; ++ ret->chat_send = oscar_chat_send; ++ ret->chat_invite = oscar_chat_invite; ++ ret->chat_leave = oscar_chat_leave; ++ ret->chat_open = oscar_chat_open; + ret->add_permit = oscar_add_permit; + ret->add_deny = oscar_add_deny; + ret->rem_permit = oscar_rem_permit; +@@ -2335,5 +2649,7 @@ + ret->keepalive = oscar_keepalive; + ret->get_status_string = oscar_get_status_string; + ++ ret->send_typing = oscar_send_typing; ++ + my_protocol = ret; + } +diff -Bur bitlbee-0.92/protocols/oscar/tlv.c bitlbee-all/protocols/oscar/tlv.c +--- bitlbee-0.92/protocols/oscar/tlv.c 2004-09-21 16:34:44.000000000 -0400 ++++ bitlbee-all/protocols/oscar/tlv.c 2005-03-26 16:48:17.000000000 -0500 +@@ -373,6 +373,31 @@ + return buflen; + } + ++int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) ++{ ++ guint8 *buf; ++ int buflen; ++ aim_bstream_t bs; ++ ++ buflen = 2 + 1 + strlen(roomname) + 2; ++ ++ if (!(buf = g_malloc(buflen))) ++ return 0; ++ ++ aim_bstream_init(&bs, buf, buflen); ++ ++ aimbs_put16(&bs, exchange); ++ aimbs_put8(&bs, strlen(roomname)); ++ aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname)); ++ aimbs_put16(&bs, instance); ++ ++ aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); ++ ++ g_free(buf); ++ ++ return 0; ++} ++ + /** + * aim_writetlvchain - Write a TLV chain into a data buffer. + * @buf: Destination buffer +diff -Bur bitlbee-0.92/protocols/util.c bitlbee-all/protocols/util.c +--- bitlbee-0.92/protocols/util.c 2004-10-10 07:24:06.000000000 -0400 ++++ bitlbee-all/protocols/util.c 2005-04-23 15:47:58.000000000 -0400 +@@ -280,7 +280,7 @@ + { "lt", '<' }, + { "gt", '>' }, + { "amp", '&' }, +- { "quot", '\'' }, ++ { "quot", '"' }, + { "dquot", '"' }, + { "aacute", 'á' }, + { "eacute", 'é' }, +@@ -325,6 +325,8 @@ + + if( *in ) + { ++ if( g_strncasecmp( cs+1, "br", 2) == 0 ) ++ *(s++) = '\n'; + in ++; + } + else +@@ -365,7 +367,40 @@ + + strcpy( start, out ); + g_free( out ); +-} ++} ++ ++char * escape_html(const char *html) ++{ ++ const char *c = html; ++ GString *ret; ++ ++ if (html == NULL) ++ return NULL; ++ ++ ret = g_string_new(""); ++ ++ while (*c) { ++ switch (*c) { ++ case '&': ++ ret = g_string_append(ret, "&"); ++ break; ++ case '<': ++ ret = g_string_append(ret, "<"); ++ break; ++ case '>': ++ ret = g_string_append(ret, ">"); ++ break; ++ case '"': ++ ret = g_string_append(ret, """); ++ break; ++ default: ++ ret = g_string_append_c(ret, *c); ++ } ++ c++; ++ } ++ ++ return g_string_free(ret, FALSE); ++} + + void info_string_append(GString *str, char *newline, char *name, char *value) + { +diff -Bur bitlbee-0.92/user.h bitlbee-all/user.h +--- bitlbee-0.92/user.h 2004-10-29 19:58:00.000000000 -0400 ++++ bitlbee-all/user.h 2005-04-16 18:08:07.000000000 -0400 +@@ -43,7 +43,7 @@ + int sendbuf_len; + guint sendbuf_timer; + +- int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg ); ++ int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags ); + + struct __USER *next; + } user_t; |