]>
Commit | Line | Data |
---|---|---|
9de3ca7e | 1 | /* |
2 | * aim_chat.c | |
3 | * | |
4 | * Routines for the Chat service. Nothing works (yet). | |
5 | * | |
6 | */ | |
7 | ||
a25832e6 | 8 | #include <faim/aim.h> |
9de3ca7e | 9 | |
0c20631f | 10 | char *aim_chat_getname(struct aim_conn_t *conn) |
11 | { | |
12 | if (!conn) | |
13 | return NULL; | |
14 | if (conn->type != AIM_CONN_TYPE_CHAT) | |
15 | return NULL; | |
16 | ||
17 | return (char *)conn->priv; /* yuck ! */ | |
18 | } | |
19 | ||
20 | struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) | |
21 | { | |
22 | int i; | |
23 | ||
24 | for (i=0;i<AIM_CONN_MAX;i++) | |
25 | { | |
26 | if (sess->conns[i].type == AIM_CONN_TYPE_CHAT) | |
27 | { | |
28 | if (sess->conns[i].priv) | |
29 | if (!strcmp((char *)sess->conns[i].priv, name)) | |
30 | { | |
31 | return &sess->conns[i]; | |
32 | } | |
33 | } | |
34 | } | |
35 | return NULL; | |
36 | } | |
37 | ||
38 | int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) | |
39 | { | |
40 | if (!conn || !roomname) | |
41 | return -1; | |
42 | ||
43 | conn->priv = malloc(strlen(roomname)+1); | |
44 | strcpy(conn->priv, roomname); | |
45 | ||
46 | return 0; | |
47 | } | |
48 | ||
49 | u_long aim_chat_send_im(struct aim_session_t *sess, | |
50 | struct aim_conn_t *conn, | |
51 | char *msg) | |
52 | { | |
53 | ||
54 | int curbyte,i; | |
55 | struct command_tx_struct newpacket; | |
56 | ||
57 | if (!sess || !conn || !msg) | |
58 | return 0; | |
59 | ||
60 | newpacket.lock = 1; /* lock struct */ | |
61 | newpacket.type = 0x02; /* IMs are always family 0x02 */ | |
62 | ||
63 | /* | |
64 | * Since we must have a specific connection, then theres | |
65 | * no use in going on if we don't have one... | |
66 | */ | |
67 | if (!conn) | |
68 | return sess->snac_nextid; | |
69 | newpacket.conn = conn; | |
70 | ||
71 | /* | |
72 | * Its simplest to set this arbitrarily large and waste | |
73 | * space. Precalculating is costly here. | |
74 | */ | |
75 | newpacket.commandlen = 1152; | |
76 | ||
77 | newpacket.data = (u_char *) calloc(1, newpacket.commandlen); | |
78 | ||
79 | curbyte = 0; | |
80 | curbyte += aim_putsnac(newpacket.data+curbyte, | |
81 | 0x000e, 0x0005, 0x0000, sess->snac_nextid); | |
82 | ||
83 | /* | |
84 | * Generate a random message cookie | |
85 | * | |
86 | */ | |
87 | for (i=0;i<8;i++) | |
88 | curbyte += aimutil_put8(newpacket.data+curbyte, (u_char) random()); | |
89 | ||
90 | /* | |
91 | * metaTLV start. -- i assume this is a metaTLV. it could be the | |
92 | * channel ID though. | |
93 | */ | |
94 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0003); | |
95 | ||
96 | /* | |
97 | * Type 1: Unknown. Blank. | |
98 | */ | |
99 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); | |
100 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); | |
101 | ||
102 | /* | |
103 | * Type 6: Unknown. Blank. | |
104 | */ | |
105 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0006); | |
106 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); | |
107 | ||
108 | /* | |
109 | * Type 5: Message block. Contains more TLVs. | |
110 | * | |
111 | * This could include other information... We just | |
112 | * put in a message TLV however. | |
113 | * | |
114 | */ | |
115 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0005); | |
116 | curbyte += aimutil_put16(newpacket.data+curbyte, strlen(msg)+4); | |
117 | ||
118 | /* | |
119 | * SubTLV: Type 1: Message | |
120 | */ | |
121 | curbyte += aim_puttlv_str(newpacket.data+curbyte, 0x0001, strlen(msg), msg); | |
122 | ||
123 | newpacket.commandlen = curbyte; | |
124 | ||
125 | newpacket.lock = 0; | |
126 | aim_tx_enqueue(sess, &newpacket); | |
127 | ||
128 | return (sess->snac_nextid++); | |
129 | } | |
130 | ||
9de3ca7e | 131 | /* |
0c20631f | 132 | * Join a room of name roomname. This is the first |
133 | * step to joining an already created room. It's | |
134 | * basically a Service Request for family 0x000e, | |
135 | * with a little added on to specify the exchange | |
136 | * and room name. | |
9de3ca7e | 137 | * |
138 | */ | |
a25832e6 | 139 | u_long aim_chat_join(struct aim_session_t *sess, |
140 | struct aim_conn_t *conn, | |
0c20631f | 141 | u_short exchange, |
a25832e6 | 142 | const char *roomname) |
9de3ca7e | 143 | { |
144 | struct command_tx_struct newpacket; | |
0c20631f | 145 | int i; |
146 | ||
147 | if (!sess || !conn || !roomname) | |
148 | return 0; | |
9de3ca7e | 149 | |
150 | newpacket.lock = 1; | |
151 | if (conn) | |
152 | newpacket.conn = conn; | |
153 | else | |
a25832e6 | 154 | newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); |
155 | ||
0c20631f | 156 | newpacket.type = 0x02; |
9de3ca7e | 157 | |
0c20631f | 158 | newpacket.commandlen = 10 + 9 + strlen(roomname) + 2; |
9de3ca7e | 159 | newpacket.data = (char *) malloc(newpacket.commandlen); |
160 | memset(newpacket.data, 0x00, newpacket.commandlen); | |
161 | ||
0c20631f | 162 | i = aim_putsnac(newpacket.data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); |
9de3ca7e | 163 | |
0c20631f | 164 | i+= aimutil_put16(newpacket.data+i, 0x000e); |
165 | ||
166 | /* | |
167 | * this is techinally a TLV, but we can't use normal functions | |
168 | * because we need the extraneous nulls and other weird things. | |
169 | */ | |
170 | i+= aimutil_put16(newpacket.data+i, 0x0001); | |
171 | i+= aimutil_put16(newpacket.data+i, 2+1+strlen(roomname)+2); | |
172 | i+= aimutil_put16(newpacket.data+i, exchange); | |
173 | i+= aimutil_put8(newpacket.data+i, strlen(roomname)); | |
174 | memcpy(newpacket.data+i, roomname, strlen(roomname)); | |
175 | i+= strlen(roomname); | |
176 | //i+= aimutil_putstr(newpacket.data+i, roomname, strlen(roomname)); | |
177 | i+= aimutil_put16(newpacket.data+i, 0x0000); | |
9de3ca7e | 178 | |
0c20631f | 179 | /* |
180 | * Chat hack. | |
181 | * | |
182 | * XXX: A problem occurs here if we request a channel | |
183 | * join but it fails....pendingjoin will be nonnull | |
184 | * even though the channel is never going to get a | |
185 | * redirect! | |
186 | * | |
187 | */ | |
188 | sess->pendingjoin = (char *)malloc(strlen(roomname)+1); | |
189 | strcpy(sess->pendingjoin, roomname); | |
190 | ||
191 | newpacket.lock = 0; | |
a25832e6 | 192 | aim_tx_enqueue(sess, &newpacket); |
9de3ca7e | 193 | |
0c20631f | 194 | #if 0 |
9de3ca7e | 195 | { |
196 | struct aim_snac_t snac; | |
197 | ||
a25832e6 | 198 | snac.id = sess->snac_nextid; |
9de3ca7e | 199 | snac.family = 0x0001; |
200 | snac.type = 0x0004; | |
201 | snac.flags = 0x0000; | |
202 | ||
0c20631f | 203 | snac.data = malloc(strlen(roomname)+1); |
204 | strcpy(snac.data, roomname); | |
9de3ca7e | 205 | |
a25832e6 | 206 | aim_newsnac(sess, &snac); |
9de3ca7e | 207 | } |
208 | ||
0c20631f | 209 | #endif |
210 | return (sess->snac_nextid++); | |
211 | } | |
212 | ||
213 | int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) | |
214 | { | |
215 | int namelen = 0; | |
216 | int i = 0; | |
217 | ||
218 | if (!buf || !outinfo) | |
219 | return 0; | |
220 | ||
221 | outinfo->exchange = aimutil_get16(buf+i); | |
222 | i += 2; | |
223 | ||
224 | namelen = aimutil_get8(buf+i); | |
225 | i += 1; | |
226 | ||
227 | outinfo->name = (char *)malloc(namelen+1); | |
228 | memcpy(outinfo->name, buf+i, namelen); | |
229 | outinfo->name[namelen] = '\0'; | |
230 | i += namelen; | |
231 | ||
232 | outinfo->instance = aimutil_get16(buf+i); | |
233 | i += 2; | |
234 | ||
235 | return i; | |
236 | }; | |
237 | ||
238 | ||
239 | /* | |
240 | * General room information. Lots of stuff. | |
241 | * | |
242 | * Values I know are in here but I havent attached | |
243 | * them to any of the 'Unknown's: | |
244 | * - Language (English) | |
245 | * | |
246 | */ | |
247 | int aim_chat_parse_infoupdate(struct aim_session_t *sess, | |
248 | struct command_rx_struct *command) | |
249 | { | |
250 | struct aim_userinfo_s *userinfo; | |
251 | rxcallback_t userfunc=NULL; | |
252 | int ret = 1, i = 0; | |
253 | int usercount = 0; | |
254 | u_char detaillevel = 0; | |
255 | char *roomname; | |
256 | struct aim_chat_roominfo roominfo; | |
257 | u_short tlvcount = 0; | |
258 | struct aim_tlvlist_t *tlvlist; | |
259 | char *roomdesc; | |
260 | ||
261 | i = 10; | |
262 | i += aim_chat_readroominfo(command->data+i, &roominfo); | |
263 | ||
264 | detaillevel = aimutil_get8(command->data+i); | |
265 | i++; | |
266 | ||
267 | tlvcount = aimutil_get16(command->data+i); | |
268 | i += 2; | |
269 | ||
270 | /* | |
271 | * Everything else are TLVs. | |
272 | */ | |
273 | tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); | |
274 | ||
275 | /* | |
276 | * TLV type 0x006a is the room name in Human Readable Form. | |
277 | */ | |
278 | if (aim_gettlv(tlvlist, 0x006a, 1)) | |
279 | roomname = aim_gettlv_str(tlvlist, 0x006a, 1); | |
280 | ||
281 | /* | |
282 | * Type 0x006f: Number of occupants. | |
283 | */ | |
284 | if (aim_gettlv(tlvlist, 0x006f, 1)) | |
285 | { | |
286 | struct aim_tlv_t *tmptlv; | |
287 | tmptlv = aim_gettlv(tlvlist, 0x006f, 1); | |
288 | ||
289 | usercount = aimutil_get16(tmptlv->value); | |
290 | } | |
291 | ||
292 | /* | |
293 | * Type 0x0073: Occupant list. | |
294 | */ | |
295 | if (aim_gettlv(tlvlist, 0x0073, 1)) | |
296 | { | |
297 | int curoccupant = 0; | |
298 | struct aim_tlv_t *tmptlv; | |
299 | ||
300 | tmptlv = aim_gettlv(tlvlist, 0x0073, 1); | |
301 | ||
302 | /* Allocate enough userinfo structs for all occupants */ | |
303 | userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); | |
304 | ||
305 | i = 0; | |
306 | while (curoccupant < usercount) | |
307 | i += aim_extractuserinfo(tmptlv->value+i, &userinfo[curoccupant++]); | |
308 | } | |
309 | ||
310 | /* | |
311 | * Type 0x00c9: Unknown. | |
312 | */ | |
313 | if (aim_gettlv(tlvlist, 0x00c9, 1)) | |
314 | ; | |
315 | ||
316 | /* | |
317 | * Type 0x00ca: Creation date | |
318 | */ | |
319 | if (aim_gettlv(tlvlist, 0x00ca, 1)) | |
320 | ; | |
321 | ||
322 | /* | |
323 | * Type 0x00d1: Maximum Message Length | |
324 | */ | |
325 | if (aim_gettlv(tlvlist, 0x00d1, 1)) | |
326 | ; | |
327 | ||
328 | /* | |
329 | * Type 0x00d2: Unknown. | |
330 | */ | |
331 | if (aim_gettlv(tlvlist, 0x00d2, 1)) | |
332 | ; | |
333 | ||
334 | /* | |
335 | * Type 0x00d3: Room Description | |
336 | */ | |
337 | if (aim_gettlv(tlvlist, 0x00d3, 1)) | |
338 | roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); | |
339 | ||
340 | /* | |
341 | * Type 0x00d5: Unknown. | |
342 | */ | |
343 | if (aim_gettlv(tlvlist, 0x00d5, 1)) | |
344 | ; | |
345 | ||
346 | ||
347 | userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE); | |
348 | if (userfunc) | |
349 | { | |
350 | ret = userfunc(sess, | |
351 | command, | |
352 | &roominfo, | |
353 | roomname, | |
354 | usercount, | |
355 | userinfo, | |
356 | roomdesc); | |
357 | } | |
358 | free(roominfo.name); | |
359 | free(userinfo); | |
360 | free(roomname); | |
361 | free(roomdesc); | |
362 | aim_freetlvchain(&tlvlist); | |
363 | ||
364 | return ret; | |
365 | } | |
366 | ||
367 | int aim_chat_parse_joined(struct aim_session_t *sess, | |
368 | struct command_rx_struct *command) | |
369 | { | |
370 | struct aim_userinfo_s *userinfo = NULL; | |
371 | rxcallback_t userfunc=NULL; | |
372 | int i = 10, curcount = 0, ret = 1; | |
373 | ||
374 | while (i < command->commandlen) | |
375 | { | |
376 | curcount++; | |
377 | userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); | |
378 | i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); | |
379 | } | |
380 | ||
381 | userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN); | |
382 | if (userfunc) | |
383 | { | |
384 | ret = userfunc(sess, | |
385 | command, | |
386 | curcount, | |
387 | userinfo); | |
388 | } | |
389 | ||
390 | free(userinfo); | |
391 | ||
392 | return ret; | |
393 | } | |
394 | ||
395 | int aim_chat_parse_leave(struct aim_session_t *sess, | |
396 | struct command_rx_struct *command) | |
397 | { | |
398 | ||
399 | struct aim_userinfo_s *userinfo = NULL; | |
400 | rxcallback_t userfunc=NULL; | |
401 | int i = 10, curcount = 0, ret = 1; | |
402 | ||
403 | while (i < command->commandlen) | |
404 | { | |
405 | curcount++; | |
406 | userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); | |
407 | i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); | |
408 | } | |
409 | ||
410 | userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE); | |
411 | if (userfunc) | |
412 | { | |
413 | ret = userfunc(sess, | |
414 | command, | |
415 | curcount, | |
416 | userinfo); | |
417 | } | |
418 | ||
419 | free(userinfo); | |
420 | ||
421 | return ret; | |
422 | } | |
423 | ||
424 | /* | |
425 | * We could probably include this in the normal ICBM parsing | |
426 | * code as channel 0x0003, however, since only the start | |
427 | * would be the same, we might as well do it here. | |
428 | */ | |
429 | int aim_chat_parse_incoming(struct aim_session_t *sess, | |
430 | struct command_rx_struct *command) | |
431 | { | |
432 | struct aim_userinfo_s userinfo; | |
433 | rxcallback_t userfunc=NULL; | |
434 | int ret = 1, i = 0, z = 0; | |
435 | u_char cookie[8]; | |
436 | int channel; | |
437 | struct aim_tlvlist_t *outerlist; | |
438 | char *msg = NULL; | |
439 | ||
440 | memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); | |
441 | ||
442 | i = 10; /* skip snac */ | |
443 | ||
444 | /* | |
445 | * ICBM Cookie. Ignore it. | |
446 | */ | |
447 | for (z=0; z<8; z++,i++) | |
448 | cookie[z] = command->data[i]; | |
449 | ||
450 | /* | |
451 | * Channel ID | |
452 | * | |
453 | * Channels 1 and 2 are implemented in the normal ICBM | |
454 | * parser. | |
455 | * | |
456 | * We only do channel 3 here. | |
457 | * | |
458 | */ | |
459 | channel = aimutil_get16(command->data+i); | |
460 | i += 2; | |
461 | ||
462 | if (channel != 0x0003) | |
463 | { | |
464 | printf("faim: chat_incoming: unknown channel! (0x%04x)\n", channel); | |
465 | return 1; | |
466 | } | |
467 | ||
468 | /* | |
469 | * Start parsing TLVs right away. | |
470 | */ | |
471 | outerlist = aim_readtlvchain(command->data+i, command->commandlen-i); | |
472 | ||
473 | /* | |
474 | * Type 0x0003: Source User Information | |
475 | */ | |
476 | if (aim_gettlv(outerlist, 0x0003, 1)) | |
477 | { | |
478 | struct aim_tlv_t *userinfotlv; | |
479 | ||
480 | userinfotlv = aim_gettlv(outerlist, 0x0003, 1); | |
481 | aim_extractuserinfo(userinfotlv->value, &userinfo); | |
482 | } | |
483 | ||
484 | /* | |
485 | * Type 0x0001: Unknown. | |
486 | */ | |
487 | if (aim_gettlv(outerlist, 0x0001, 1)) | |
488 | ; | |
489 | ||
490 | /* | |
491 | * Type 0x0005: Message Block. Conains more TLVs. | |
492 | */ | |
493 | if (aim_gettlv(outerlist, 0x0005, 1)) | |
494 | { | |
495 | struct aim_tlvlist_t *innerlist; | |
496 | struct aim_tlv_t *msgblock; | |
497 | ||
498 | msgblock = aim_gettlv(outerlist, 0x0005, 1); | |
499 | innerlist = aim_readtlvchain(msgblock->value, msgblock->length); | |
500 | ||
501 | /* | |
502 | * Type 0x0001: Message. | |
503 | */ | |
504 | if (aim_gettlv(innerlist, 0x0001, 1)) | |
505 | msg = aim_gettlv_str(innerlist, 0x0001, 1); | |
506 | ||
507 | aim_freetlvchain(&innerlist); | |
508 | } | |
509 | ||
510 | userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG); | |
511 | if (userfunc) | |
512 | { | |
513 | ret = userfunc(sess, | |
514 | command, | |
515 | &userinfo, | |
516 | msg); | |
517 | } | |
518 | free(msg); | |
519 | aim_freetlvchain(&outerlist); | |
520 | ||
521 | return ret; | |
522 | } | |
523 | ||
524 | u_long aim_chat_clientready(struct aim_session_t *sess, | |
525 | struct aim_conn_t *conn) | |
526 | { | |
527 | struct command_tx_struct newpacket; | |
528 | int i; | |
529 | ||
530 | newpacket.lock = 1; | |
531 | if (conn) | |
532 | newpacket.conn = conn; | |
533 | else | |
534 | newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_CHAT); | |
535 | newpacket.type = 0x02; | |
536 | newpacket.commandlen = 0x20; | |
537 | ||
538 | newpacket.data = (char *) malloc(newpacket.commandlen); | |
539 | i = aim_putsnac(newpacket.data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); | |
540 | ||
541 | i+= aimutil_put16(newpacket.data+i, 0x000e); | |
542 | i+= aimutil_put16(newpacket.data+i, 0x0001); | |
543 | ||
544 | i+= aimutil_put16(newpacket.data+i, 0x0004); | |
545 | i+= aimutil_put16(newpacket.data+i, 0x0001); | |
546 | ||
547 | i+= aimutil_put16(newpacket.data+i, 0x0001); | |
548 | i+= aimutil_put16(newpacket.data+i, 0x0003); | |
549 | ||
550 | i+= aimutil_put16(newpacket.data+i, 0x0004); | |
551 | i+= aimutil_put16(newpacket.data+i, 0x0686); | |
552 | ||
553 | newpacket.lock = 0; | |
554 | aim_tx_enqueue(sess, &newpacket); | |
555 | ||
556 | return (sess->snac_nextid++); | |
557 | } | |
558 | ||
559 | int aim_chat_leaveroom(struct aim_session_t *sess, char *name) | |
560 | { | |
561 | int i; | |
562 | ||
563 | for (i=0;i<AIM_CONN_MAX;i++) | |
564 | { | |
565 | if (sess->conns[i].type == AIM_CONN_TYPE_CHAT) | |
566 | { | |
567 | if (sess->conns[i].priv) | |
568 | if (!strcmp((char *)sess->conns[i].priv, name)) | |
569 | { | |
570 | aim_conn_close(&sess->conns[i]); | |
571 | return 0; | |
572 | } | |
573 | } | |
574 | } | |
575 | return -1; | |
576 | } | |
577 | ||
578 | /* | |
579 | * conn must be a BOS connection! | |
580 | */ | |
581 | u_long aim_chat_invite(struct aim_session_t *sess, | |
582 | struct aim_conn_t *conn, | |
583 | char *sn, | |
584 | char *msg, | |
585 | u_short exchange, | |
586 | char *roomname, | |
587 | u_short instance) | |
588 | { | |
589 | struct command_tx_struct newpacket; | |
590 | int i,curbyte=0; | |
591 | ||
592 | if (!sess || !conn || !sn || !msg || !roomname) | |
593 | return 0; | |
594 | ||
595 | newpacket.lock = 1; | |
596 | if (conn) | |
597 | newpacket.conn = conn; | |
598 | else | |
599 | newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); | |
600 | newpacket.type = 0x02; | |
601 | newpacket.commandlen = 1152+strlen(sn)+strlen(roomname)+strlen(msg); | |
602 | ||
603 | newpacket.data = (char *) malloc(newpacket.commandlen); | |
604 | curbyte = aim_putsnac(newpacket.data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); | |
605 | ||
606 | /* | |
607 | * Cookie | |
608 | */ | |
609 | for (i=0;i<8;i++) | |
610 | curbyte += aimutil_put8(newpacket.data+curbyte, (u_char)rand()); | |
611 | ||
612 | /* | |
613 | * Channel (2) | |
614 | */ | |
615 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); | |
616 | ||
617 | /* | |
618 | * Dest sn | |
619 | */ | |
620 | curbyte += aimutil_put8(newpacket.data+curbyte, strlen(sn)); | |
621 | curbyte += aimutil_putstr(newpacket.data+curbyte, sn, strlen(sn)); | |
622 | ||
623 | /* | |
624 | * TLV t(0005) | |
625 | */ | |
626 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0005); | |
627 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02); | |
628 | ||
629 | /* | |
630 | * Unknown info | |
631 | */ | |
632 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); | |
633 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x3131); | |
634 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x3538); | |
635 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x3446); | |
636 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x4100); | |
637 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x748f); | |
638 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x2420); | |
639 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x6287); | |
640 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x11d1); | |
641 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x8222); | |
642 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x4445); | |
643 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x5354); | |
644 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); | |
645 | ||
646 | /* | |
647 | * TLV t(000a) -- Unknown | |
648 | */ | |
649 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x000a); | |
650 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); | |
651 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); | |
652 | ||
653 | /* | |
654 | * TLV t(000f) -- Unknown | |
655 | */ | |
656 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x000f); | |
657 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); | |
658 | ||
659 | /* | |
660 | * TLV t(000c) -- Invitation message | |
661 | */ | |
662 | curbyte += aim_puttlv_str(newpacket.data+curbyte, 0x000c, strlen(msg), msg); | |
663 | ||
664 | /* | |
665 | * TLV t(2711) -- Container for room information | |
666 | */ | |
667 | curbyte += aimutil_put16(newpacket.data+curbyte, 0x2711); | |
668 | curbyte += aimutil_put16(newpacket.data+curbyte, 3+strlen(roomname)+2); | |
669 | curbyte += aimutil_put16(newpacket.data+curbyte, exchange); | |
670 | curbyte += aimutil_put8(newpacket.data+curbyte, strlen(roomname)); | |
671 | curbyte += aimutil_putstr(newpacket.data+curbyte, roomname, strlen(roomname)); | |
672 | curbyte += aimutil_put16(newpacket.data+curbyte, instance); | |
673 | ||
674 | newpacket.commandlen = curbyte; | |
675 | newpacket.lock = 0; | |
676 | aim_tx_enqueue(sess, &newpacket); | |
677 | ||
a25832e6 | 678 | return (sess->snac_nextid++); |
9de3ca7e | 679 | } |