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