]> andersk Git - libfaim.git/blob - aim_chat.c
- Sun Apr 2 01:45:15 UTC 2000
[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   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
131 /*
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.
137  *
138  */
139 u_long aim_chat_join(struct aim_session_t *sess,
140                      struct aim_conn_t *conn, 
141                      u_short exchange,
142                      const char *roomname)
143 {
144   struct command_tx_struct newpacket;
145   int i;
146
147   if (!sess || !conn || !roomname)
148     return 0;
149   
150   newpacket.lock = 1;
151   if (conn)
152     newpacket.conn = conn;
153   else
154     newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
155
156   newpacket.type = 0x02;
157   
158   newpacket.commandlen = 10 + 9 + strlen(roomname) + 2;
159   newpacket.data = (char *) malloc(newpacket.commandlen);
160   memset(newpacket.data, 0x00, newpacket.commandlen);
161   
162   i = aim_putsnac(newpacket.data, 0x0001, 0x0004, 0x0000, sess->snac_nextid);
163
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);
178
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;
192   aim_tx_enqueue(sess, &newpacket);
193
194 #if 0
195   {
196     struct aim_snac_t snac;
197     
198     snac.id = sess->snac_nextid;
199     snac.family = 0x0001;
200     snac.type = 0x0004;
201     snac.flags = 0x0000;
202
203     snac.data = malloc(strlen(roomname)+1);
204     strcpy(snac.data, roomname);
205
206     aim_newsnac(sess, &snac);
207   }
208
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 = NULL;
251   rxcallback_t userfunc=NULL;   
252   int ret = 1, i = 0;
253   int usercount = 0;
254   u_char detaillevel = 0;
255   char *roomname = NULL;
256   struct aim_chat_roominfo roominfo;
257   u_short tlvcount = 0;
258   struct aim_tlvlist_t *tlvlist;
259   char *roomdesc = NULL;
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
678   return (sess->snac_nextid++);
679 }
This page took 0.133062 seconds and 5 git commands to generate.