Mercurial > pidgin.yaz
annotate libfaim/chat.c @ 1771:213607e89598
[gaim-migrate @ 1781]
plug mem leak. don't show evil level if it decreased. mid's utf8 patch for jabber. my girlfriend got an accounting calculator today, you know, with the paper and the printing and things. it's kinda loud. she's really happy about having it. she had bought a different one yesterday but it didn't work so we returned it today. we also went to Albertson's and bought groceries. we bought 72 cans of soda for $15. That's 20 cents per soda. Not bad. we also bought a cow; i'm going to cook it tonight. ben&jerry's ice cream is good.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Mon, 30 Apr 2001 01:25:30 +0000 |
parents | bacb77b0eb06 |
children | 109cacf1ff97 |
rev | line source |
---|---|
1535 | 1 /* |
2 * aim_chat.c | |
3 * | |
4 * Routines for the Chat service. | |
5 * | |
6 */ | |
7 | |
8 #define FAIM_INTERNAL | |
9 #include <aim.h> | |
10 | |
11 faim_export char *aim_chat_getname(struct aim_conn_t *conn) | |
12 { | |
13 if (!conn) | |
14 return NULL; | |
15 if (conn->type != AIM_CONN_TYPE_CHAT) | |
16 return NULL; | |
17 | |
18 return (char *)conn->priv; /* yuck ! */ | |
19 } | |
20 | |
21 faim_export struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) | |
22 { | |
23 struct aim_conn_t *cur; | |
24 | |
25 faim_mutex_lock(&sess->connlistlock); | |
26 for (cur = sess->connlist; cur; cur = cur->next) { | |
27 if (cur->type != AIM_CONN_TYPE_CHAT) | |
28 continue; | |
29 if (!cur->priv) { | |
30 faimdprintf(sess, 0, "faim: chat: chat connection with no name! (fd = %d)\n", cur->fd); | |
31 continue; | |
32 } | |
33 if (strcmp((char *)cur->priv, name) == 0) | |
34 break; | |
35 } | |
36 faim_mutex_unlock(&sess->connlistlock); | |
37 | |
38 return cur; | |
39 } | |
40 | |
41 faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) | |
42 { | |
43 if (!conn || !roomname) | |
44 return -1; | |
45 | |
46 if (conn->priv) | |
47 free(conn->priv); | |
48 | |
49 conn->priv = strdup(roomname); | |
50 | |
51 return 0; | |
52 } | |
53 | |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
54 /* |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
55 * Send a Chat Message. |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
56 * |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
57 * Possible flags: |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
58 * AIM_CHATFLAGS_NOREFLECT -- Unset the flag that requests messages |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
59 * should be sent to their sender. |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
60 * AIM_CHATFLAGS_AWAY -- Mark the message as an autoresponse |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
61 * (Note that WinAIM does not honor this, |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
62 * and displays the message as normal.) |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
63 * |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
64 * XXX convert this to use tlvchains |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
65 */ |
1535 | 66 faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, |
67 struct aim_conn_t *conn, | |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
68 unsigned short flags, |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
69 const char *msg, |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
70 int msglen) |
1535 | 71 { |
72 | |
73 int curbyte,i; | |
74 struct command_tx_struct *newpacket; | |
75 struct aim_msgcookie_t *cookie; | |
76 | |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
77 if (!sess || !conn || !msg || (msglen <= 0)) |
1535 | 78 return 0; |
79 | |
80 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) | |
81 return -1; | |
82 | |
83 newpacket->lock = 1; /* lock struct */ | |
84 | |
85 curbyte = 0; | |
86 curbyte += aim_putsnac(newpacket->data+curbyte, | |
87 0x000e, 0x0005, 0x0000, sess->snac_nextid); | |
88 | |
89 /* | |
90 * Generate a random message cookie | |
91 */ | |
92 for (i=0;i<8;i++) | |
93 curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) rand()); | |
94 | |
95 cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_CHAT, NULL); | |
96 cookie->data = strdup(conn->priv); /* chat hack dependent */ | |
97 | |
98 aim_cachecookie(sess, cookie); | |
99 | |
100 /* | |
101 * Channel ID. | |
102 */ | |
103 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); | |
104 | |
105 /* | |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
106 * Type 1: Flag meaning this message is destined to the room. |
1535 | 107 */ |
108 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); | |
109 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); | |
110 | |
111 /* | |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
112 * Type 6: Reflect |
1535 | 113 */ |
1746
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
114 if (!(flags & AIM_CHATFLAGS_NOREFLECT)) { |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
115 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
116 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
117 } |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
118 |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
119 /* |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
120 * Type 7: Autoresponse |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
121 */ |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
122 if (flags & AIM_CHATFLAGS_AWAY) { |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
123 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007); |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
124 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); |
bacb77b0eb06
[gaim-migrate @ 1756]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1649
diff
changeset
|
125 } |
1535 | 126 |
127 /* | |
128 * Type 5: Message block. Contains more TLVs. | |
129 * | |
130 * This could include other information... We just | |
131 * put in a message TLV however. | |
132 * | |
133 */ | |
134 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); | |
135 curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg)+4); | |
136 | |
137 /* | |
138 * SubTLV: Type 1: Message | |
139 */ | |
140 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(msg), msg); | |
141 | |
142 newpacket->commandlen = curbyte; | |
143 | |
144 newpacket->lock = 0; | |
145 aim_tx_enqueue(sess, newpacket); | |
146 | |
147 return (sess->snac_nextid++); | |
148 } | |
149 | |
150 /* | |
151 * Join a room of name roomname. This is the first | |
152 * step to joining an already created room. It's | |
153 * basically a Service Request for family 0x000e, | |
154 * with a little added on to specify the exchange | |
155 * and room name. | |
156 * | |
157 */ | |
158 faim_export unsigned long aim_chat_join(struct aim_session_t *sess, | |
159 struct aim_conn_t *conn, | |
160 u_short exchange, | |
161 const char *roomname) | |
162 { | |
163 struct command_tx_struct *newpacket; | |
164 int i; | |
165 | |
166 if (!sess || !conn || !roomname) | |
167 return 0; | |
168 | |
169 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+9+strlen(roomname)+2))) | |
170 return -1; | |
171 | |
172 newpacket->lock = 1; | |
173 | |
174 i = aim_putsnac(newpacket->data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); | |
175 | |
176 i+= aimutil_put16(newpacket->data+i, 0x000e); | |
177 | |
178 /* | |
179 * this is techinally a TLV, but we can't use normal functions | |
180 * because we need the extraneous nulls and other weird things. | |
181 */ | |
182 i+= aimutil_put16(newpacket->data+i, 0x0001); | |
183 i+= aimutil_put16(newpacket->data+i, 2+1+strlen(roomname)+2); | |
184 i+= aimutil_put16(newpacket->data+i, exchange); | |
185 i+= aimutil_put8(newpacket->data+i, strlen(roomname)); | |
186 i+= aimutil_putstr(newpacket->data+i, roomname, strlen(roomname)); | |
187 i+= aimutil_put16(newpacket->data+i, 0x0000); /* instance? */ | |
188 | |
189 /* | |
190 * Chat hack. | |
191 * | |
192 * XXX: A problem occurs here if we request a channel | |
193 * join but it fails....pendingjoin will be nonnull | |
194 * even though the channel is never going to get a | |
195 * redirect! | |
196 * | |
197 */ | |
198 sess->pendingjoin = strdup(roomname); | |
199 sess->pendingjoinexchange = exchange; | |
200 | |
201 newpacket->lock = 0; | |
202 aim_tx_enqueue(sess, newpacket); | |
203 | |
204 aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, roomname, strlen(roomname)+1); | |
205 | |
206 return sess->snac_nextid; | |
207 } | |
208 | |
209 faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) | |
210 { | |
211 int namelen = 0; | |
212 int i = 0; | |
213 | |
214 if (!buf || !outinfo) | |
215 return 0; | |
216 | |
217 outinfo->exchange = aimutil_get16(buf+i); | |
218 i += 2; | |
219 | |
220 namelen = aimutil_get8(buf+i); | |
221 i += 1; | |
222 | |
223 outinfo->name = (char *)malloc(namelen+1); | |
224 memcpy(outinfo->name, buf+i, namelen); | |
225 outinfo->name[namelen] = '\0'; | |
226 i += namelen; | |
227 | |
228 outinfo->instance = aimutil_get16(buf+i); | |
229 i += 2; | |
230 | |
231 return i; | |
232 } | |
233 | |
234 faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, | |
235 struct aim_conn_t *conn) | |
236 { | |
237 struct command_tx_struct *newpacket; | |
238 int i; | |
239 | |
240 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) | |
241 return -1; | |
242 | |
243 newpacket->lock = 1; | |
244 | |
245 i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); | |
246 | |
247 i+= aimutil_put16(newpacket->data+i, 0x000e); | |
248 i+= aimutil_put16(newpacket->data+i, 0x0001); | |
249 | |
250 i+= aimutil_put16(newpacket->data+i, 0x0004); | |
251 i+= aimutil_put16(newpacket->data+i, 0x0001); | |
252 | |
253 i+= aimutil_put16(newpacket->data+i, 0x0001); | |
254 i+= aimutil_put16(newpacket->data+i, 0x0003); | |
255 | |
256 i+= aimutil_put16(newpacket->data+i, 0x0004); | |
257 i+= aimutil_put16(newpacket->data+i, 0x0686); | |
258 | |
259 newpacket->lock = 0; | |
260 aim_tx_enqueue(sess, newpacket); | |
261 | |
262 return (sess->snac_nextid++); | |
263 } | |
264 | |
265 faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name) | |
266 { | |
267 struct aim_conn_t *conn; | |
268 | |
269 if ((conn = aim_chat_getconn(sess, name))) | |
270 aim_conn_close(conn); | |
271 | |
272 if (!conn) | |
273 return -1; | |
274 return 0; | |
275 } | |
276 | |
277 /* | |
278 * conn must be a BOS connection! | |
279 */ | |
280 faim_export unsigned long aim_chat_invite(struct aim_session_t *sess, | |
281 struct aim_conn_t *conn, | |
282 char *sn, | |
283 char *msg, | |
284 u_short exchange, | |
285 char *roomname, | |
286 u_short instance) | |
287 { | |
288 struct command_tx_struct *newpacket; | |
289 int i,curbyte=0; | |
290 struct aim_msgcookie_t *cookie; | |
291 struct aim_invite_priv *priv; | |
292 | |
293 if (!sess || !conn || !sn || !msg || !roomname) | |
294 return -1; | |
295 | |
296 if (conn->type != AIM_CONN_TYPE_BOS) | |
297 return -1; | |
298 | |
299 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) | |
300 return -1; | |
301 | |
302 newpacket->lock = 1; | |
303 | |
304 curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); | |
305 | |
306 /* | |
307 * Cookie | |
308 */ | |
309 for (i=0;i<8;i++) | |
310 curbyte += aimutil_put8(newpacket->data+curbyte, (u_char)rand()); | |
311 | |
312 /* XXX this should get uncached by the unwritten 'invite accept' handler */ | |
313 if(!(priv = calloc(sizeof(struct aim_invite_priv), 1))) | |
314 return -1; | |
315 priv->sn = strdup(sn); | |
316 priv->roomname = strdup(roomname); | |
317 priv->exchange = exchange; | |
318 priv->instance = instance; | |
319 | |
320 if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv))) | |
321 return -1; | |
322 aim_cachecookie(sess, cookie); | |
323 | |
324 /* | |
325 * Channel (2) | |
326 */ | |
327 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); | |
328 | |
329 /* | |
330 * Dest sn | |
331 */ | |
332 curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); | |
333 curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); | |
334 | |
335 /* | |
336 * TLV t(0005) | |
337 */ | |
338 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); | |
339 curbyte += aimutil_put16(newpacket->data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02); | |
340 | |
341 /* | |
342 * Unknown info | |
343 */ | |
344 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); | |
345 curbyte += aimutil_put16(newpacket->data+curbyte, 0x3131); | |
346 curbyte += aimutil_put16(newpacket->data+curbyte, 0x3538); | |
347 curbyte += aimutil_put16(newpacket->data+curbyte, 0x3446); | |
348 curbyte += aimutil_put16(newpacket->data+curbyte, 0x4100); | |
349 curbyte += aimutil_put16(newpacket->data+curbyte, 0x748f); | |
350 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2420); | |
351 curbyte += aimutil_put16(newpacket->data+curbyte, 0x6287); | |
352 curbyte += aimutil_put16(newpacket->data+curbyte, 0x11d1); | |
353 curbyte += aimutil_put16(newpacket->data+curbyte, 0x8222); | |
354 curbyte += aimutil_put16(newpacket->data+curbyte, 0x4445); | |
355 curbyte += aimutil_put16(newpacket->data+curbyte, 0x5354); | |
356 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); | |
357 | |
358 /* | |
359 * TLV t(000a) -- Unknown | |
360 */ | |
361 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); | |
362 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); | |
363 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); | |
364 | |
365 /* | |
366 * TLV t(000f) -- Unknown | |
367 */ | |
368 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); | |
369 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); | |
370 | |
371 /* | |
372 * TLV t(000c) -- Invitation message | |
373 */ | |
374 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000c, strlen(msg), msg); | |
375 | |
376 /* | |
377 * TLV t(2711) -- Container for room information | |
378 */ | |
379 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); | |
380 curbyte += aimutil_put16(newpacket->data+curbyte, 3+strlen(roomname)+2); | |
381 curbyte += aimutil_put16(newpacket->data+curbyte, exchange); | |
382 curbyte += aimutil_put8(newpacket->data+curbyte, strlen(roomname)); | |
383 curbyte += aimutil_putstr(newpacket->data+curbyte, roomname, strlen(roomname)); | |
384 curbyte += aimutil_put16(newpacket->data+curbyte, instance); | |
385 | |
386 newpacket->commandlen = curbyte; | |
387 newpacket->lock = 0; | |
388 aim_tx_enqueue(sess, newpacket); | |
389 | |
390 return (sess->snac_nextid++); | |
391 } | |
1649 | 392 |
393 /* | |
394 * General room information. Lots of stuff. | |
395 * | |
396 * Values I know are in here but I havent attached | |
397 * them to any of the 'Unknown's: | |
398 * - Language (English) | |
399 * | |
400 * SNAC 000e/0002 | |
401 */ | |
402 static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) | |
403 { | |
404 struct aim_userinfo_s *userinfo = NULL; | |
405 rxcallback_t userfunc=NULL; | |
406 int ret = 0, i = 0; | |
407 int usercount = 0; | |
408 unsigned char detaillevel = 0; | |
409 char *roomname = NULL; | |
410 struct aim_chat_roominfo roominfo; | |
411 unsigned short tlvcount = 0; | |
412 struct aim_tlvlist_t *tlvlist; | |
413 char *roomdesc = NULL; | |
414 unsigned short unknown_c9 = 0; | |
415 unsigned long creationtime = 0; | |
416 unsigned short maxmsglen = 0; | |
417 unsigned short unknown_d2 = 0, unknown_d5 = 0; | |
418 | |
419 i += aim_chat_readroominfo(data+i, &roominfo); | |
420 | |
421 detaillevel = aimutil_get8(data+i); | |
422 i++; | |
423 | |
424 if (detaillevel != 0x02) { | |
425 if (detaillevel == 0x01) | |
426 faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level 1 not supported\n"); | |
427 else | |
428 faimdprintf(sess, 0, "faim: chat_roomupdateinfo: unknown detail level %d\n", detaillevel); | |
429 return 1; | |
430 } | |
431 | |
432 tlvcount = aimutil_get16(data+i); | |
433 i += 2; | |
434 | |
435 /* | |
436 * Everything else are TLVs. | |
437 */ | |
438 tlvlist = aim_readtlvchain(data+i, datalen-i); | |
439 | |
440 /* | |
441 * TLV type 0x006a is the room name in Human Readable Form. | |
442 */ | |
443 if (aim_gettlv(tlvlist, 0x006a, 1)) | |
444 roomname = aim_gettlv_str(tlvlist, 0x006a, 1); | |
445 | |
446 /* | |
447 * Type 0x006f: Number of occupants. | |
448 */ | |
449 if (aim_gettlv(tlvlist, 0x006f, 1)) | |
450 usercount = aim_gettlv16(tlvlist, 0x006f, 1); | |
451 | |
452 /* | |
453 * Type 0x0073: Occupant list. | |
454 */ | |
455 if (aim_gettlv(tlvlist, 0x0073, 1)) { | |
456 int curoccupant = 0; | |
457 struct aim_tlv_t *tmptlv; | |
458 | |
459 tmptlv = aim_gettlv(tlvlist, 0x0073, 1); | |
460 | |
461 /* Allocate enough userinfo structs for all occupants */ | |
462 userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); | |
463 | |
464 i = 0; | |
465 while (curoccupant < usercount) | |
466 i += aim_extractuserinfo(sess, tmptlv->value+i, &userinfo[curoccupant++]); | |
467 } | |
468 | |
469 /* | |
470 * Type 0x00c9: Unknown. (2 bytes) | |
471 */ | |
472 if (aim_gettlv(tlvlist, 0x00c9, 1)) | |
473 unknown_c9 = aim_gettlv16(tlvlist, 0x00c9, 1); | |
474 | |
475 /* | |
476 * Type 0x00ca: Creation time (4 bytes) | |
477 */ | |
478 if (aim_gettlv(tlvlist, 0x00ca, 1)) | |
479 creationtime = aim_gettlv32(tlvlist, 0x00ca, 1); | |
480 | |
481 /* | |
482 * Type 0x00d1: Maximum Message Length | |
483 */ | |
484 if (aim_gettlv(tlvlist, 0x00d1, 1)) | |
485 maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1); | |
486 | |
487 /* | |
488 * Type 0x00d2: Unknown. (2 bytes) | |
489 */ | |
490 if (aim_gettlv(tlvlist, 0x00d2, 1)) | |
491 unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1); | |
492 | |
493 /* | |
494 * Type 0x00d3: Room Description | |
495 */ | |
496 if (aim_gettlv(tlvlist, 0x00d3, 1)) | |
497 roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); | |
498 | |
499 /* | |
500 * Type 0x00d5: Unknown. (1 byte) | |
501 */ | |
502 if (aim_gettlv(tlvlist, 0x00d5, 1)) | |
503 unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1); | |
504 | |
505 | |
506 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { | |
507 ret = userfunc(sess, | |
508 rx, | |
509 &roominfo, | |
510 roomname, | |
511 usercount, | |
512 userinfo, | |
513 roomdesc, | |
514 unknown_c9, | |
515 creationtime, | |
516 maxmsglen, | |
517 unknown_d2, | |
518 unknown_d5); | |
519 } | |
520 | |
521 free(roominfo.name); | |
522 free(userinfo); | |
523 free(roomname); | |
524 free(roomdesc); | |
525 aim_freetlvchain(&tlvlist); | |
526 | |
527 return ret; | |
528 } | |
529 | |
530 static int userlistchange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) | |
531 { | |
532 struct aim_userinfo_s *userinfo = NULL; | |
533 rxcallback_t userfunc; | |
534 int i = 0, curcount = 0, ret = 0; | |
535 | |
536 while (i < datalen) { | |
537 curcount++; | |
538 userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); | |
539 i += aim_extractuserinfo(sess, data+i, &userinfo[curcount-1]); | |
540 } | |
541 | |
542 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
543 ret = userfunc(sess, rx, curcount, userinfo); | |
544 | |
545 free(userinfo); | |
546 | |
547 return ret; | |
548 } | |
549 | |
550 /* | |
551 * We could probably include this in the normal ICBM parsing | |
552 * code as channel 0x0003, however, since only the start | |
553 * would be the same, we might as well do it here. | |
554 * | |
555 * General outline of this SNAC: | |
556 * snac | |
557 * cookie | |
558 * channel id | |
559 * tlvlist | |
560 * unknown | |
561 * source user info | |
562 * name | |
563 * evility | |
564 * userinfo tlvs | |
565 * online time | |
566 * etc | |
567 * message metatlv | |
568 * message tlv | |
569 * message string | |
570 * possibly others | |
571 * | |
572 */ | |
573 static int incomingmsg(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) | |
574 { | |
575 struct aim_userinfo_s userinfo; | |
576 rxcallback_t userfunc=NULL; | |
577 int ret = 0, i = 0; | |
578 unsigned char cookie[8]; | |
579 int channel; | |
580 struct aim_tlvlist_t *outerlist; | |
581 char *msg = NULL; | |
582 struct aim_msgcookie_t *ck; | |
583 | |
584 memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); | |
585 | |
586 /* | |
587 * ICBM Cookie. Cache it. | |
588 */ | |
589 memcpy(cookie, data, 8); | |
590 i += 8; | |
591 | |
592 if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { | |
593 if (ck->data) | |
594 free(ck->data); | |
595 free(ck); | |
596 } | |
597 | |
598 /* | |
599 * Channel ID | |
600 * | |
601 * Channels 1 and 2 are implemented in the normal ICBM | |
602 * parser. | |
603 * | |
604 * We only do channel 3 here. | |
605 * | |
606 */ | |
607 channel = aimutil_get16(data+i); | |
608 i += 2; | |
609 | |
610 if (channel != 0x0003) { | |
611 faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); | |
612 return 0; | |
613 } | |
614 | |
615 /* | |
616 * Start parsing TLVs right away. | |
617 */ | |
618 outerlist = aim_readtlvchain(data+8+2, datalen-8-2); | |
619 | |
620 /* | |
621 * Type 0x0003: Source User Information | |
622 */ | |
623 if (aim_gettlv(outerlist, 0x0003, 1)) { | |
624 struct aim_tlv_t *userinfotlv; | |
625 | |
626 userinfotlv = aim_gettlv(outerlist, 0x0003, 1); | |
627 aim_extractuserinfo(sess, userinfotlv->value, &userinfo); | |
628 } | |
629 | |
630 /* | |
631 * Type 0x0001: Unknown. | |
632 */ | |
633 if (aim_gettlv(outerlist, 0x0001, 1)) | |
634 ; | |
635 | |
636 /* | |
637 * Type 0x0005: Message Block. Conains more TLVs. | |
638 */ | |
639 if (aim_gettlv(outerlist, 0x0005, 1)) { | |
640 struct aim_tlvlist_t *innerlist; | |
641 struct aim_tlv_t *msgblock; | |
642 | |
643 msgblock = aim_gettlv(outerlist, 0x0005, 1); | |
644 innerlist = aim_readtlvchain(msgblock->value, msgblock->length); | |
645 | |
646 /* | |
647 * Type 0x0001: Message. | |
648 */ | |
649 if (aim_gettlv(innerlist, 0x0001, 1)) | |
650 msg = aim_gettlv_str(innerlist, 0x0001, 1); | |
651 | |
652 aim_freetlvchain(&innerlist); | |
653 } | |
654 | |
655 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
656 ret = userfunc(sess, rx, &userinfo, msg); | |
657 | |
658 free(msg); | |
659 aim_freetlvchain(&outerlist); | |
660 | |
661 return ret; | |
662 } | |
663 | |
664 static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) | |
665 { | |
666 | |
667 if (snac->subtype == 0x0002) | |
668 return infoupdate(sess, mod, rx, snac, data, datalen); | |
669 else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) | |
670 return userlistchange(sess, mod, rx, snac, data, datalen); | |
671 else if (snac->subtype == 0x0006) | |
672 return incomingmsg(sess, mod, rx, snac, data, datalen); | |
673 | |
674 return 0; | |
675 } | |
676 | |
677 faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod) | |
678 { | |
679 | |
680 mod->family = 0x000e; | |
681 mod->version = 0x0000; | |
682 mod->flags = 0; | |
683 strncpy(mod->name, "chat", sizeof(mod->name)); | |
684 mod->snachandler = snachandler; | |
685 | |
686 return 0; | |
687 } |