2 * Purple's oscar protocol plugin
3 * This file is the legal property of its developers.
4 * Please see the AUTHORS file distributed alongside this file.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 * Family 0x000e - Routines for the Chat service.
30 /* Stored in the ->internal of chat connections */
39 flap_connection_destroy_chat(OscarData
*od
, FlapConnection
*conn
)
41 struct chatconnpriv
*ccp
= (struct chatconnpriv
*)conn
->internal
;
51 aim_chat_readroominfo(ByteStream
*bs
, struct aim_chat_roominfo
*outinfo
)
56 outinfo
->exchange
= byte_stream_get16(bs
);
57 outinfo
->namelen
= byte_stream_get8(bs
);
58 outinfo
->name
= (char *)byte_stream_getraw(bs
, outinfo
->namelen
);
59 outinfo
->instance
= byte_stream_get16(bs
);
65 * Subtype 0x0002 - General room information. Lots of stuff.
67 * Values I know are in here but I haven't attached
68 * them to any of the 'Unknown's:
69 * - Language (English)
73 infoupdate(OscarData
*od
, FlapConnection
*conn
, aim_module_t
*mod
, FlapFrame
*frame
, aim_modsnac_t
*snac
, ByteStream
*bs
)
75 aim_rxcallback_t userfunc
;
77 guint8 detaillevel
= 0;
78 struct aim_chat_roominfo roominfo
;
80 guint16 maxmsglen
, maxvisiblemsglen
;
82 aim_chat_readroominfo(bs
, &roominfo
);
84 detaillevel
= byte_stream_get8(bs
);
86 if (detaillevel
!= 0x02) {
87 purple_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel
);
91 byte_stream_get16(bs
); /* skip the TLV count */
94 * Everything else are TLVs.
96 tlvlist
= aim_tlvlist_read(bs
);
99 * Type 0x00d1: Maximum Message Length
101 maxmsglen
= aim_tlv_get16(tlvlist
, 0x00d1, 1);
104 * Type 0x00da: Maximum visible message length
106 maxvisiblemsglen
= aim_tlv_get16(tlvlist
, 0x00da, 1);
108 if ((userfunc
= aim_callhandler(od
, snac
->family
, snac
->subtype
))) {
109 ret
= userfunc(od
, conn
, frame
, maxmsglen
, maxvisiblemsglen
);
112 g_free(roominfo
.name
);
114 aim_tlvlist_free(tlvlist
);
119 /* Subtypes 0x0003 and 0x0004 */
121 userlistchange(OscarData
*od
, FlapConnection
*conn
, aim_module_t
*mod
, FlapFrame
*frame
, aim_modsnac_t
*snac
, ByteStream
*bs
)
123 aim_userinfo_t
*userinfo
= NULL
;
124 aim_rxcallback_t userfunc
;
125 int curcount
= 0, ret
= 0;
127 while (byte_stream_bytes_left(bs
)) {
129 userinfo
= g_realloc(userinfo
, curcount
* sizeof(aim_userinfo_t
));
130 aim_info_extract(od
, bs
, &userinfo
[curcount
-1]);
133 if ((userfunc
= aim_callhandler(od
, snac
->family
, snac
->subtype
)))
134 ret
= userfunc(od
, conn
, frame
, curcount
, userinfo
);
136 aim_info_free(userinfo
);
143 * Subtype 0x0005 - Send a Chat Message.
146 * AIM_CHATFLAGS_NOREFLECT -- Unset the flag that requests messages
147 * should be sent to their sender.
148 * AIM_CHATFLAGS_AWAY -- Mark the message as an autoresponse
149 * (Note that WinAIM does not honor this,
150 * and displays the message as normal.)
152 * XXX convert this to use tlvchains
155 aim_chat_send_im(OscarData
*od
, FlapConnection
*conn
, guint16 flags
, const gchar
*msg
, int msglen
, const char *encoding
, const char *language
)
162 GSList
*tlvlist
= NULL
, *inner_tlvlist
= NULL
;
164 if (!od
|| !conn
|| !msg
|| (msglen
<= 0))
167 byte_stream_new(&bs
, 1142);
169 snacid
= aim_cachesnac(od
, SNAC_FAMILY_CHAT
, 0x0005, 0x0000, NULL
, 0);
174 * XXX mkcookie should generate the cookie and cache it in one
175 * operation to preserve uniqueness.
177 for (i
= 0; i
< 8; i
+= 4) {
178 gint32 rnd
= g_random_int();
179 ckstr
[i
] = (guint8
)((rnd
& 0xFF000000) >> 24);
180 ckstr
[i
+1] = (guint8
)((rnd
& 0xFF0000) >> 16);
181 ckstr
[i
+2] = (guint8
)((rnd
& 0xFF00) >> 8);
182 ckstr
[i
+3] = (guint8
)(rnd
& 0xFF);
185 cookie
= aim_mkcookie(ckstr
, AIM_COOKIETYPE_CHAT
, NULL
);
186 cookie
->data
= NULL
; /* XXX store something useful here */
188 aim_cachecookie(od
, cookie
);
191 byte_stream_putraw(&bs
, ckstr
, 8); /* Cookie */
192 byte_stream_put16(&bs
, 0x0003); /* Channel */
195 * Type 1: Flag meaning this message is destined to the room.
197 aim_tlvlist_add_noval(&tlvlist
, 0x0001);
202 if (!(flags
& AIM_CHATFLAGS_NOREFLECT
))
203 aim_tlvlist_add_noval(&tlvlist
, 0x0006);
206 * Type 7: Autoresponse
208 if (flags
& AIM_CHATFLAGS_AWAY
)
209 aim_tlvlist_add_noval(&tlvlist
, 0x0007);
212 * SubTLV: Type 1: Message
214 aim_tlvlist_add_raw(&inner_tlvlist
, 0x0001, msglen
, (guchar
*)msg
);
217 * SubTLV: Type 2: Encoding
219 if (encoding
!= NULL
)
220 aim_tlvlist_add_str(&inner_tlvlist
, 0x0002, encoding
);
223 * SubTLV: Type 3: Language
225 if (language
!= NULL
)
226 aim_tlvlist_add_str(&inner_tlvlist
, 0x0003, language
);
229 * Type 5: Message block. Contains more TLVs.
231 * This could include other information... We just
232 * put in a message TLV however.
235 aim_tlvlist_add_frozentlvlist(&tlvlist
, 0x0005, &inner_tlvlist
);
237 aim_tlvlist_write(&bs
, &tlvlist
);
239 aim_tlvlist_free(inner_tlvlist
);
240 aim_tlvlist_free(tlvlist
);
242 flap_connection_send_snac(od
, conn
, SNAC_FAMILY_CHAT
, 0x0005, snacid
, &bs
);
244 byte_stream_destroy(&bs
);
252 * We could probably include this in the normal ICBM parsing
253 * code as channel 0x0003, however, since only the start
254 * would be the same, we might as well do it here.
256 * General outline of this SNAC:
275 incomingim_ch3(OscarData
*od
, FlapConnection
*conn
, aim_module_t
*mod
, FlapFrame
*frame
, aim_modsnac_t
*snac
, ByteStream
*bs
)
278 aim_rxcallback_t userfunc
;
279 aim_userinfo_t userinfo
;
285 char *encoding
= NULL
, *language
= NULL
;
290 memset(&userinfo
, 0, sizeof(aim_userinfo_t
));
295 for (i
= 0; i
< 8; i
++)
296 cookie
[i
] = byte_stream_get8(bs
);
298 if ((ck
= aim_uncachecookie(od
, cookie
, AIM_COOKIETYPE_CHAT
))) {
306 * Channel 0x0003 is used for chat messages.
309 channel
= byte_stream_get16(bs
);
311 if (channel
!= 0x0003) {
312 purple_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel
);
317 * Start parsing TLVs right away.
319 tlvlist
= aim_tlvlist_read(bs
);
322 * Type 0x0003: Source User Information
324 tlv
= aim_tlv_gettlv(tlvlist
, 0x0003, 1);
327 byte_stream_init(&tbs
, tlv
->value
, tlv
->length
);
328 aim_info_extract(od
, &tbs
, &userinfo
);
332 * Type 0x0005: Message Block. Conains more TLVs.
334 tlv
= aim_tlv_gettlv(tlvlist
, 0x0005, 1);
337 GSList
*inner_tlvlist
;
338 aim_tlv_t
*inner_tlv
;
340 byte_stream_init(&tbs
, tlv
->value
, tlv
->length
);
341 inner_tlvlist
= aim_tlvlist_read(&tbs
);
344 * Type 0x0001: Message.
346 inner_tlv
= aim_tlv_gettlv(inner_tlvlist
, 0x0001, 1);
347 if (inner_tlv
!= NULL
)
349 len
= inner_tlv
->length
;
350 msg
= aim_tlv_getvalue_as_string(inner_tlv
);
354 * Type 0x0002: Encoding.
356 encoding
= aim_tlv_getstr(inner_tlvlist
, 0x0002, 1);
359 * Type 0x0003: Language.
361 language
= aim_tlv_getstr(inner_tlvlist
, 0x0003, 1);
363 aim_tlvlist_free(inner_tlvlist
);
366 if ((userfunc
= aim_callhandler(od
, snac
->family
, snac
->subtype
)))
367 ret
= userfunc(od
, conn
, frame
, &userinfo
, len
, msg
, encoding
, language
);
369 aim_info_free(&userinfo
);
373 aim_tlvlist_free(tlvlist
);
379 snachandler(OscarData
*od
, FlapConnection
*conn
, aim_module_t
*mod
, FlapFrame
*frame
, aim_modsnac_t
*snac
, ByteStream
*bs
)
381 if (snac
->subtype
== 0x0002)
382 return infoupdate(od
, conn
, mod
, frame
, snac
, bs
);
383 else if ((snac
->subtype
== 0x0003) || (snac
->subtype
== 0x0004))
384 return userlistchange(od
, conn
, mod
, frame
, snac
, bs
);
385 else if (snac
->subtype
== 0x0006)
386 return incomingim_ch3(od
, conn
, mod
, frame
, snac
, bs
);
392 chat_modfirst(OscarData
*od
, aim_module_t
*mod
)
394 mod
->family
= SNAC_FAMILY_CHAT
;
395 mod
->version
= 0x0001;
396 mod
->toolid
= 0x0010;
397 mod
->toolversion
= 0x0629;
399 strncpy(mod
->name
, "chat", sizeof(mod
->name
));
400 mod
->snachandler
= snachandler
;