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