diff options
Diffstat (limited to 'protocols/oscar')
| -rw-r--r-- | protocols/oscar/Makefile | 7 | ||||
| -rw-r--r-- | protocols/oscar/auth.c | 3 | ||||
| -rw-r--r-- | protocols/oscar/oscar.c | 276 | 
3 files changed, 109 insertions, 177 deletions
| diff --git a/protocols/oscar/Makefile b/protocols/oscar/Makefile index 2792f22a..c1a966ad 100644 --- a/protocols/oscar/Makefile +++ b/protocols/oscar/Makefile @@ -7,11 +7,14 @@  ### DEFINITIONS  -include ../../Makefile.settings +ifdef SRCDIR +SRCDIR := $(SRCDIR)protocols/oscar/ +CFLAGS += -I$(SRCDIR) +endif  # [SH] Program variables  objects = admin.o auth.o bos.o buddylist.o chat.o chatnav.o conn.o icq.o im.o info.o misc.o msgcookie.o rxhandlers.o rxqueue.o search.o service.o snac.o ssi.o stats.o tlv.o txqueue.o oscar_util.o oscar.o -CFLAGS += -Wall  LFLAGS += -r  # [SH] Phony targets @@ -32,7 +35,7 @@ distclean: clean  $(objects): ../../Makefile.settings Makefile -$(objects): %.o: %.c +$(objects): %.o: $(SRCDIR)%.c  	@echo '*' Compiling $<  	@$(CC) -c $(CFLAGS) $< -o $@ diff --git a/protocols/oscar/auth.c b/protocols/oscar/auth.c index eb6a9d64..0f7c8d0f 100644 --- a/protocols/oscar/auth.c +++ b/protocols/oscar/auth.c @@ -119,11 +119,12 @@ int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn)  	aim_frame_t *fr;  	aim_snacid_t snacid;  	aim_tlvlist_t *tl = NULL; +	struct im_connection *ic = sess->aux_data;  	if (!sess || !conn || !sn)  		return -EINVAL; -	if ((sn[0] >= '0') && (sn[0] <= '9')) +	if (isdigit(sn[0]) && set_getbool(&ic->acc->set, "old_icq_auth"))  		return goddamnicq(sess, conn, sn);  	sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index f0e65f9a..3f5272cd 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 *, ...); @@ -254,8 +253,6 @@ static char *normalize(const char *s)  	g_return_val_if_fail((s != NULL), NULL);  	u = t = g_strdup(s); - -	strcpy(t, s);  	g_strdown(t);  	while (*t && (x < BUF_LEN - 1)) { @@ -290,7 +287,7 @@ static gboolean oscar_callback(gpointer data, gint source,  	odata = (struct oscar_data *)ic->proto_data; -	if (condition & GAIM_INPUT_READ) { +	if (condition & B_EV_IO_READ) {  		if (aim_get_command(odata->sess, conn) >= 0) {  			aim_rxdispatch(odata->sess);                                 if (odata->killme) @@ -362,7 +359,7 @@ static gboolean oscar_login_connect(gpointer data, gint source, b_input_conditio  	}  	aim_conn_completeconnect(sess, conn); -	ic->inpa = b_input_add(conn->fd, GAIM_INPUT_READ, +	ic->inpa = b_input_add(conn->fd, B_EV_IO_READ,  			oscar_callback, conn);  	return FALSE; @@ -372,11 +369,16 @@ static void oscar_init(account_t *acc)  {  	set_t *s; -	s = set_add( &acc->set, "server", AIM_DEFAULT_LOGIN_SERVER, set_eval_account, acc ); +	if (isdigit(acc->user[0])) { +		set_add(&acc->set, "ignore_auth_requests", "false", set_eval_bool, acc); +		set_add(&acc->set, "old_icq_auth", "false", set_eval_bool, acc); +	} +	 +	s = set_add(&acc->set, "server", AIM_DEFAULT_LOGIN_SERVER, set_eval_account, acc);  	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; -	if (isdigit(acc->user[0])) { -		s = set_add( &acc->set, "web_aware", "false", set_eval_bool, acc ); +	if(isdigit(acc->user[0])) { +		s = set_add(&acc->set, "web_aware", "false", set_eval_bool, acc);  		s->flags |= ACC_SET_OFFLINE_ONLY;  	} @@ -488,7 +490,7 @@ static gboolean oscar_bos_connect(gpointer data, gint source, b_input_condition  	}  	aim_conn_completeconnect(sess, bosconn); -	ic->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ, +	ic->inpa = b_input_add(bosconn->fd, B_EV_IO_READ,  			oscar_callback, bosconn);  	imcb_log(ic, _("Connection established, cookie sent")); @@ -565,7 +567,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); @@ -599,143 +600,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}; @@ -782,6 +649,7 @@ static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) {  static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) {  	struct im_connection *ic = sess->aux_data;  	struct chat_connection *chatcon; +	struct groupchat *c = NULL;  	static int id = 1;  	aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, gaim_parse_genericerr, 0); @@ -794,7 +662,12 @@ static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) {  	chatcon = find_oscar_chat_by_conn(ic, fr->conn);  	chatcon->id = id; -	chatcon->cnv = imcb_chat_new(ic, chatcon->show); +	 +	c = bee_chat_by_title(ic->bee, ic, chatcon->show); +	if (c && !c->data) +		chatcon->cnv = c; +	else +		chatcon->cnv = imcb_chat_new(ic, chatcon->show);  	chatcon->cnv->data = chatcon;  	return 1; @@ -833,7 +706,7 @@ static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condit  	}  	aim_conn_completeconnect(sess, tstconn); -	odata->cnpa = b_input_add(tstconn->fd, GAIM_INPUT_READ, +	odata->cnpa = b_input_add(tstconn->fd, B_EV_IO_READ,  					oscar_callback, tstconn);  	return FALSE; @@ -861,7 +734,7 @@ static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition  	}  	aim_conn_completeconnect(sess, tstconn); -	odata->paspa = b_input_add(tstconn->fd, GAIM_INPUT_READ, +	odata->paspa = b_input_add(tstconn->fd, B_EV_IO_READ,  				oscar_callback, tstconn);  	return FALSE; @@ -897,7 +770,7 @@ static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition  	aim_conn_completeconnect(sess, ccon->conn);  	ccon->inpa = b_input_add(tstconn->fd, -			GAIM_INPUT_READ, +			B_EV_IO_READ,  			oscar_callback, tstconn);  	odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon); @@ -1064,7 +937,7 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {  	tmp = normalize(info->sn);  	imcb_buddy_status(ic, tmp, flags, state_string, NULL); -	/* imcb_buddy_times(ic, tmp, signon, time_idle); */ +	imcb_buddy_times(ic, tmp, signon, time_idle);  	return 1; @@ -1161,16 +1034,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; @@ -1185,8 +1063,7 @@ static void gaim_icq_authgrant(void *data_) {  	message = 0;  	aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");  	// aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message); -	if(imcb_find_buddy(data->ic, uin) == NULL) -		imcb_ask_add(data->ic, uin, NULL); +	imcb_ask_add(data->ic, uin, NULL);  	g_free(uin);  	g_free(data); @@ -1211,10 +1088,15 @@ static void gaim_icq_authdeny(void *data_) {   * For when other people ask you for authorization   */  static void gaim_icq_authask(struct im_connection *ic, guint32 uin, char *msg) { -	struct icq_auth *data = g_new(struct icq_auth, 1); +	struct icq_auth *data;  	char *reason = NULL;  	char *dialog_msg; + +	if (set_getbool(&ic->acc->set, "ignore_auth_requests")) +		return; +	data = g_new(struct icq_auth, 1); +  	if (strlen(msg) > 6)  		reason = msg + 6; @@ -1942,11 +1824,13 @@ static void oscar_get_info(struct im_connection *g, char *name) {  static void oscar_get_away(struct im_connection *g, char *who) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data;  	if (odata->icq) { +		/** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?  		struct buddy *budlight = imcb_find_buddy(g, who);  		if (budlight)  			if ((budlight->uc & 0xff80) >> 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_AWAYMESSAGE);  } @@ -2058,7 +1942,12 @@ static void oscar_set_away(struct im_connection *ic, char *state, char *message)  static void oscar_add_buddy(struct im_connection *g, char *name, char *group) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data; -	aim_ssi_addbuddies(odata->sess, odata->conn, OSCAR_GROUP, &name, 1, 0); +	bee_user_t *bu; +	 +	if (group && (bu = bee_user_by_handle(g->bee, g, name)) && bu->group) +		aim_ssi_movebuddy(odata->sess, odata->conn, bu->group->name, group, name); +	else +		aim_ssi_addbuddies(odata->sess, odata->conn, group ? : OSCAR_GROUP, &name, 1, 0);  }  static void oscar_remove_buddy(struct im_connection *g, char *name, char *group) { @@ -2073,7 +1962,7 @@ static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  	struct im_connection *ic = sess->aux_data; -	struct aim_ssi_item *curitem; +	struct aim_ssi_item *curitem, *curgroup = NULL;  	int tmp;  	char *nrm; @@ -2084,13 +1973,13 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  		switch (curitem->type) {  			case 0x0000: /* Buddy */ -				if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) { +				if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {  					char *realname = NULL;  					if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))  						    realname = aim_gettlv_str(curitem->data, 0x0131, 1); -						 -					imcb_add_buddy(ic, nrm, NULL); +					 +					imcb_add_buddy(ic, nrm, curgroup ? (curgroup->gid == curitem->gid ? curgroup->name : NULL) : NULL);  					if (realname) {  						imcb_buddy_nick_hint(ic, nrm, realname); @@ -2100,6 +1989,10 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  				}  				break; +			case 0x0001: /* Group */ +				curgroup = curitem; +				break; +  			case 0x0002: /* Permit buddy */  				if (curitem->name) {  					GSList *list; @@ -2178,10 +2071,13 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... )  		list = (char *) origsnac->data;  		for( i = 0; i < count; i ++ )  		{ +			struct aim_ssi_item *ssigroup = aim_ssi_itemlist_findparent( sess->ssi.items, list ); +			char *group = ssigroup ? ssigroup->name : NULL; +			  			st = aimbs_get16( &fr->data );  			if( st == 0x00 )  			{ -				imcb_add_buddy( sess->aux_data, normalize(list), NULL ); +				imcb_add_buddy( sess->aux_data, normalize(list), group );  			}  			else if( st == 0x0E )  			{ @@ -2329,7 +2225,7 @@ static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)  			g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email2[i]);  		}  	} -	if ((ip = (long) g_hash_table_lookup(od->ips, &info->uin)) != 0) { +	if (od->ips && (ip = (long) g_hash_table_lookup(od->ips, &info->uin)) != 0) {  		g_string_append_printf(str, "\n%s: %d.%d.%d.%d", _("Last used IP address"),  		                       (ip >> 24), (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);  	} @@ -2542,7 +2438,8 @@ void oscar_chat_msg(struct groupchat *c, char *message, int msgflags)  	guint16 flags;  	char *s; -	ccon = c->data; +	if (!(ccon = c->data)) +		return;  	for (s = message; *s; s++)  		if (*s & 128) @@ -2583,7 +2480,10 @@ void oscar_chat_invite(struct groupchat *c, char *who, char *message)  {  	struct im_connection *ic = c->ic;  	struct oscar_data * od = (struct oscar_data *)ic->proto_data; -	struct chat_connection *ccon = c->data; +	struct chat_connection *ccon; +	 +	if (!(ccon = c->data)) +		return;  	aim_chat_invite(od->sess, od->conn, who, message ? message : "",  					ccon->exchange, ccon->name, 0x0); @@ -2608,43 +2508,59 @@ void oscar_chat_kill(struct im_connection *ic, struct chat_connection *cc)  void oscar_chat_leave(struct groupchat *c)  { +	if (!c->data) +		return;  	oscar_chat_kill(c->ic, c->data);  } -struct groupchat *oscar_chat_join(struct im_connection * ic, const char * room, const char * nick, const char * password ) +struct groupchat *oscar_chat_join_internal(struct im_connection *ic, const char *room, +	const char *nick, const char *password, int exchange_number)  {  	struct oscar_data * od = (struct oscar_data *)ic->proto_data; +	struct groupchat *ret = imcb_chat_new(ic, room);  	aim_conn_t * cur;  	if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) {  		int st; -		st = aim_chatnav_createroom(od->sess, cur, room, 4); +		st = aim_chatnav_createroom(od->sess, cur, room, exchange_number); -		return NULL; +		return ret;  	} else {  		struct create_room * cr = g_new0(struct create_room, 1); -		cr->exchange = 4; +		cr->exchange = exchange_number;  		cr->name = g_strdup(room);  		od->create_rooms = g_slist_append(od->create_rooms, cr);  		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV); -		return NULL; +		return ret;  	}  } +struct groupchat *oscar_chat_join(struct im_connection *ic, const char *room, +	const char *nick, const char *password, set_t **sets) +{ +	return oscar_chat_join_internal(ic, room, nick, password, set_getint(sets, "exchange_number")); +} +  struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)  {  	struct oscar_data * od = (struct oscar_data *)ic->proto_data;  	struct groupchat *ret;  	static int chat_id = 0; -	char * chatname; +	char * chatname, *s; +	struct groupchat *c; -	chatname = g_strdup_printf("%s%d", ic->acc->user, chat_id++); -   -	ret = oscar_chat_join(ic, chatname, NULL, NULL); - +	chatname = g_strdup_printf("%s%s%d", isdigit(*ic->acc->user) ? "icq" : "", +	                           ic->acc->user, chat_id++); +	 +	for (s = chatname; *s; s ++) +		if (!isalnum(*s)) +			*s = '0'; +	 +	c = imcb_chat_new(ic, chatname); +	ret = oscar_chat_join_internal(ic, chatname, NULL, NULL, 4);  	aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);  	g_free(chatname); @@ -2656,7 +2572,7 @@ void oscar_accept_chat(void *data)  {  	struct aim_chat_invitation * inv = data; -	oscar_chat_join(inv->ic, inv->name, NULL, NULL); +	oscar_chat_join_internal(inv->ic, inv->name, NULL, NULL, 4);  	g_free(inv->name);  	g_free(inv);  } @@ -2669,6 +2585,16 @@ void oscar_reject_chat(void *data)  	g_free(inv);  } +void oscar_chat_add_settings(account_t *acc, set_t **head) +{ +	set_add(head, "exchange_number", "4", set_eval_int, NULL); +} + +void oscar_chat_free_settings(account_t *acc, set_t **head) +{ +	set_del(head, "exchange_number"); +} +  void oscar_initmodule()   {  	struct prpl *ret = g_new0(struct prpl, 1); @@ -2689,6 +2615,8 @@ void oscar_initmodule()  	ret->chat_leave = oscar_chat_leave;  	ret->chat_with = oscar_chat_with;  	ret->chat_join = oscar_chat_join; +	ret->chat_add_settings = oscar_chat_add_settings; +	ret->chat_free_settings = oscar_chat_free_settings;  	ret->add_permit = oscar_add_permit;  	ret->add_deny = oscar_add_deny;  	ret->rem_permit = oscar_rem_permit; | 
