]> andersk Git - libfaim.git/blob - aim_tlv.c
- Fri Feb 9 22:31:22 UTC 2001
[libfaim.git] / aim_tlv.c
1
2 #define FAIM_INTERNAL
3 #include <faim/aim.h>
4
5 /**
6  * aim_readtlvchain - Read a TLV chain from a buffer.
7  * @buf: Input buffer
8  * @maxlen: Length of input buffer
9  *
10  * Reads and parses a series of TLV patterns from a data buffer; the
11  * returned structure is manipulatable with the rest of the TLV
12  * routines.  When done with a TLV chain, aim_freetlvchain() should
13  * be called to free the dynamic substructures.
14  *
15  */
16 faim_export struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
17 {
18   int pos;
19   struct aim_tlvlist_t *list;
20   struct aim_tlvlist_t *cur;
21   
22   u_short type;
23   u_short length;
24
25   if (!buf)
26     return NULL;
27
28   list = NULL;
29   
30   pos = 0;
31
32   while (pos < maxlen)
33     {
34       type = aimutil_get16(buf+pos);
35       pos += 2;
36
37       if (pos < maxlen)
38         {
39           length = aimutil_get16(buf+pos);
40           pos += 2;
41           
42           if ((pos+length) <= maxlen)
43             {
44               /*
45                * Okay, so now AOL has decided that any TLV of
46                * type 0x0013 can only be two bytes, despite
47                * what the actual given length is.  So here 
48                * we dump any invalid TLVs of that sort.  Hopefully
49                * theres no special cases to this special case.
50                *   - mid (30jun2000)
51                */
52               if ((type == 0x0013) && (length != 0x0002)) {
53                 printf("faim: skipping TLV t(0013) with invalid length (0x%04x)\n", length);
54                 length = 0x0002;
55               } else {
56                 cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
57                 memset(cur, 0x00, sizeof(struct aim_tlvlist_t));
58
59                 cur->tlv = aim_createtlv();     
60                 cur->tlv->type = type;
61                 cur->tlv->length = length; 
62                 if (length) {
63                   cur->tlv->value = (unsigned char *)malloc(length);
64                   memcpy(cur->tlv->value, buf+pos, length);
65                 } 
66
67                 cur->next = list;
68                 list = cur;
69               }
70               pos += length;
71             }
72         }
73     }
74
75   return list;
76 }
77
78 /**
79  * aim_freetlvchain - Free a TLV chain structure
80  * @list: Chain to be freed
81  *
82  * Walks the list of TLVs in the passed TLV chain and
83  * frees each one. Note that any references to this data
84  * should be removed before calling this.
85  *
86  */
87 faim_export void aim_freetlvchain(struct aim_tlvlist_t **list)
88 {
89   struct aim_tlvlist_t *cur, *cur2;
90
91   if (!list || !(*list))
92     return;
93
94   cur = *list;
95   while (cur)
96     {
97       aim_freetlv(&cur->tlv);
98       cur2 = cur->next;
99       free(cur);
100       cur = cur2;
101     }
102   list = NULL;
103   return;
104 }
105
106 /**
107  * aim_counttlvchain - Count the number of TLVs in a chain
108  * @list: Chain to be counted
109  *
110  * Returns the number of TLVs stored in the passed chain.
111  *
112  */
113 faim_export int aim_counttlvchain(struct aim_tlvlist_t **list)
114 {
115   struct aim_tlvlist_t *cur;
116   int count = 0;
117
118   if (!list || !(*list))
119     return 0;
120
121   for (cur = *list; cur; cur = cur->next)
122     count++;
123  
124   return count;
125 }
126
127 /**
128  * aim_sizetlvchain - Count the number of bytes in a TLV chain
129  * @list: Chain to be sized
130  *
131  * Returns the number of bytes that would be needed to 
132  * write the passed TLV chain to a data buffer.
133  *
134  */
135 faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list)
136 {
137   struct aim_tlvlist_t *cur;
138   int size = 0;
139
140   if (!list || !(*list))
141     return 0;
142
143   for (cur = *list; cur; cur = cur->next)
144     size += (4 + cur->tlv->length);
145  
146   return size;
147 }
148
149 /**
150  * aim_addtlvtochain_str - Add a string to a TLV chain
151  * @list: Desination chain (%NULL pointer if empty)
152  * @type: TLV type
153  * @str: String to add
154  * @len: Length of string to add (not including %NULL)
155  *
156  * Adds the passed string as a TLV element of the passed type
157  * to the TLV chain.
158  *
159  */
160 faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len)
161 {
162   struct aim_tlvlist_t *newtlv;
163   struct aim_tlvlist_t *cur;
164
165   if (!list)
166     return 0;
167
168   newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
169   memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
170
171   newtlv->tlv = aim_createtlv();        
172   newtlv->tlv->type = type;
173   newtlv->tlv->length = len;
174   newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char));
175   memcpy(newtlv->tlv->value, str, newtlv->tlv->length);
176
177   newtlv->next = NULL;
178
179   if (*list == NULL) {
180     *list = newtlv;
181   } else if ((*list)->next == NULL) {
182     (*list)->next = newtlv;
183   } else {
184     for(cur = *list; cur->next; cur = cur->next)
185       ;
186     cur->next = newtlv;
187   }
188   return newtlv->tlv->length;
189 }
190
191 /**
192  * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
193  * @list: Destination chain
194  * @type: TLV type to add
195  * @val: Value to add
196  *
197  * Adds a two-byte unsigned integer to a TLV chain.
198  *
199  */
200 faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val)
201 {
202   struct aim_tlvlist_t *newtl;
203   struct aim_tlvlist_t *cur;
204
205   if (!list)
206     return 0;
207
208   newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
209   memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
210
211   newtl->tlv = aim_createtlv(); 
212   newtl->tlv->type = type;
213   newtl->tlv->length = 2;
214   newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
215   aimutil_put16(newtl->tlv->value, val);
216
217   newtl->next = NULL;
218
219   if (*list == NULL) {
220     *list = newtl;
221   } else if ((*list)->next == NULL) {
222     (*list)->next = newtl;
223   } else {
224     for(cur = *list; cur->next; cur = cur->next)
225       ;
226     cur->next = newtl;
227   }
228   return 2;
229 }
230
231 /**
232  * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
233  * @list: Destination chain
234  * @type: TLV type to add
235  * @val: Value to add
236  *
237  * Adds a four-byte unsigned integer to a TLV chain.
238  *
239  */
240 faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val)
241 {
242   struct aim_tlvlist_t *newtl;
243   struct aim_tlvlist_t *cur;
244
245   if (!list)
246     return 0;
247
248   newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
249   memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
250
251   newtl->tlv = aim_createtlv(); 
252   newtl->tlv->type = type;
253   newtl->tlv->length = 4;
254   newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
255   aimutil_put32(newtl->tlv->value, val);
256
257   newtl->next = NULL;
258
259   if (*list == NULL) {
260     *list = newtl;
261   } else if ((*list)->next == NULL) {
262     (*list)->next = newtl;
263   } else {
264     for(cur = *list; cur->next; cur = cur->next)
265       ;
266     cur->next = newtl;
267   }
268   return 4;
269 }
270
271 /**
272  * aim_addtlvtochain_caps - Add a capability block to a TLV chain
273  * @list: Destination chain
274  * @type: TLV type to add
275  * @caps: Bitfield of capability flags to send
276  *
277  * Adds a block of capability blocks to a TLV chain. The bitfield
278  * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
279  *
280  *      %AIM_CAPS_BUDDYICON   Supports Buddy Icons
281  *
282  *      %AIM_CAPS_VOICE       Supports Voice Chat
283  *
284  *      %AIM_CAPS_IMIMAGE     Supports DirectIM/IMImage
285  *
286  *      %AIM_CAPS_CHAT        Supports Chat
287  *
288  *      %AIM_CAPS_GETFILE     Supports Get File functions
289  *
290  *      %AIM_CAPS_SENDFILE    Supports Send File functions
291  *
292  */
293 faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, unsigned short type, unsigned short caps)
294 {
295   unsigned char buf[128]; /* icky fixed length buffer */
296   struct aim_tlvlist_t *newtl;
297   struct aim_tlvlist_t *cur;
298
299   if(!list)
300     return 0;
301
302   newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
303   memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
304
305   newtl->tlv = aim_createtlv(); 
306   newtl->tlv->type = type;
307
308   newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps);
309   newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length);
310   memcpy(newtl->tlv->value, buf, newtl->tlv->length);
311
312   newtl->next = NULL;
313
314   if (*list == NULL) {
315     *list = newtl;
316   } else if ((*list)->next == NULL) {
317     (*list)->next = newtl;
318   } else {
319     for(cur = *list; cur->next; cur = cur->next)
320       ;
321     cur->next = newtl;
322   }
323   return newtl->tlv->length;
324 }
325
326 /**
327  * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
328  * @list: Destination chain
329  * @type: TLV type to add
330  *
331  * Adds a TLV with a zero length to a TLV chain.
332  *
333  */
334 faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, unsigned short type)
335 {
336   struct aim_tlvlist_t *newtlv;
337   struct aim_tlvlist_t *cur;
338
339   newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
340   memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
341
342   newtlv->tlv = aim_createtlv();        
343   newtlv->tlv->type = type;
344   newtlv->tlv->length = 0;
345   newtlv->tlv->value = NULL;
346
347   newtlv->next = NULL;
348
349   if (*list == NULL) {
350     *list = newtlv;
351   } else if ((*list)->next == NULL) {
352     (*list)->next = newtlv;
353   } else {
354     for(cur = *list; cur->next; cur = cur->next)
355       ;
356     cur->next = newtlv;
357   }
358   return newtlv->tlv->length;
359 }
360
361 /**
362  * aim_writetlvchain - Write a TLV chain into a data buffer.
363  * @buf: Destination buffer
364  * @buflen: Maximum number of bytes that will be written to buffer
365  * @list: Source TLV chain
366  *
367  * Copies a TLV chain into a raw data buffer, writing only the number
368  * of bytes specified. This operation does not free the chain; 
369  * aim_freetlvchain() must still be called to free up the memory used
370  * by the chain structures.
371  *
372  */
373 faim_export int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list)
374 {
375   int goodbuflen = 0;
376   int i = 0;
377   struct aim_tlvlist_t *cur;
378
379   if (!list || !buf || !buflen)
380     return 0;
381
382   /* do an initial run to test total length */
383   for (cur = *list; cur; cur = cur->next) {
384     goodbuflen += 2 + 2; /* type + len */
385     goodbuflen += cur->tlv->length;
386   }
387
388   if (goodbuflen > buflen)
389     return 0; /* not enough buffer */
390
391   /* do the real write-out */
392   for (cur = *list; cur; cur = cur->next) {
393     i += aimutil_put16(buf+i, cur->tlv->type);
394     i += aimutil_put16(buf+i, cur->tlv->length);
395     memcpy(buf+i, cur->tlv->value, cur->tlv->length);
396     i += cur->tlv->length;
397   }
398
399   return i;
400 }
401
402
403 /**
404  * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
405  * @list: Source chain
406  * @type: Requested TLV type
407  * @nth: Index of TLV of type to get
408  *
409  * Returns a pointer to an aim_tlv_t of the specified type; 
410  * %NULL on error.  The @nth parameter is specified starting at %1.
411  * In most cases, there will be no more than one TLV of any type
412  * in a chain.
413  *
414  */
415 faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
416 {
417   int i;
418   struct aim_tlvlist_t *cur;
419   
420   i = 0;
421   for (cur = list; cur != NULL; cur = cur->next)
422     {
423       if (cur && cur->tlv)
424         {
425           if (cur->tlv->type == type)
426             i++;
427           if (i >= nth)
428             return cur->tlv;
429         }
430     }
431   return NULL;
432 }
433
434 /**
435  * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
436  * @list: Source TLV chain
437  * @type: TLV type to search for
438  * @nth: Index of TLV to return
439  *
440  * Same as aim_gettlv(), except that the return value is a %NULL-
441  * terminated string instead of an aim_tlv_t.  This is a 
442  * dynamic buffer and must be freed by the caller.
443  *
444  */
445 faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
446 {
447   struct aim_tlv_t *tlv;
448   char *newstr;
449
450   if (!(tlv = aim_gettlv(list, type, nth)))
451     return NULL;
452   
453   newstr = (char *) malloc(tlv->length + 1);
454   memcpy(newstr, tlv->value, tlv->length);
455   *(newstr + tlv->length) = '\0';
456
457   return newstr;
458 }
459
460 /**
461  * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
462  * @list: Source TLV chain
463  * @type: TLV type to search for
464  * @nth: Index of TLV to return
465  *
466  * Same as aim_gettlv(), except that the return value is a 
467  * 8bit integer instead of an aim_tlv_t. 
468  *
469  */
470 faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, unsigned short type, int num)
471 {
472   struct aim_tlv_t *tlv;
473
474   if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
475     return 0; /* erm */
476   return aimutil_get8(tlv->value);
477 }
478
479 /**
480  * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
481  * @list: Source TLV chain
482  * @type: TLV type to search for
483  * @nth: Index of TLV to return
484  *
485  * Same as aim_gettlv(), except that the return value is a 
486  * 16bit integer instead of an aim_tlv_t. 
487  *
488  */
489 faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, unsigned short type, int num)
490 {
491   struct aim_tlv_t *tlv;
492
493   if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
494     return 0; /* erm */
495   return aimutil_get16(tlv->value);
496 }
497
498 /**
499  * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
500  * @list: Source TLV chain
501  * @type: TLV type to search for
502  * @nth: Index of TLV to return
503  *
504  * Same as aim_gettlv(), except that the return value is a 
505  * 32bit integer instead of an aim_tlv_t. 
506  *
507  */
508 faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, unsigned short type, int num)
509 {
510   struct aim_tlv_t *tlv;
511
512   if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
513     return 0; /* erm */
514   return aimutil_get32(tlv->value);
515 }
516
517 /**
518  * aim_grabtlv - Grab a single TLV from a data buffer
519  * @src: Source data buffer (must be at least 4 bytes long)
520  *
521  * Creates a TLV structure aim_tlv_t and returns it
522  * filled with values from a buffer, possibly including a 
523  * dynamically allocated buffer for the value portion.
524  *
525  * Both the aim_tlv_t and the tlv->value pointer
526  * must be freed by the caller if non-%NULL.
527  *
528  */
529 faim_export struct aim_tlv_t *aim_grabtlv(u_char *src)
530 {
531   struct aim_tlv_t *dest = NULL;
532
533   dest = aim_createtlv();
534
535   dest->type = src[0] << 8;
536   dest->type += src[1];
537
538   dest->length = src[2] << 8;
539   dest->length += src[3];
540
541   dest->value = (u_char *) malloc(dest->length*sizeof(u_char));
542   memset(dest->value, 0, dest->length*sizeof(u_char));
543
544   memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
545   
546   return dest;
547 }
548
549 /**
550  * aim_grabtlvstr - Grab a single TLV from a data buffer as string
551  * @src: Source data buffer (must be at least 4 bytes long)
552  *
553  * Creates a TLV structure aim_tlv_t and returns it
554  * filled with values from a buffer, possibly including a 
555  * dynamically allocated buffer for the value portion, which 
556  * is %NULL-terminated as a string.
557  *
558  * Both the aim_tlv_t and the tlv->value pointer
559  * must be freed by the caller if non-%NULL.
560  *
561  */
562 faim_export struct aim_tlv_t *aim_grabtlvstr(u_char *src)
563 {
564   struct aim_tlv_t *dest = NULL;
565
566   dest = aim_createtlv();
567
568   dest->type = src[0] << 8;
569   dest->type += src[1];
570
571   dest->length = src[2] << 8;
572   dest->length += src[3];
573
574   dest->value = (u_char *) malloc((dest->length+1)*sizeof(u_char));
575   memset(dest->value, 0, (dest->length+1)*sizeof(u_char));
576
577   memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
578   dest->value[dest->length] = '\0';
579
580   return dest;
581 }
582
583 /**
584  * aim_puttlv - Write a aim_tlv_t into a data buffer
585  * @dest: Destination data buffer
586  * @newtlv: Source TLV structure
587  *
588  * Writes out the passed TLV structure into the buffer. No bounds
589  * checking is done on the output buffer.
590  *
591  * The passed aim_tlv_t is not freed. aim_freetlv() should
592  * still be called by the caller to free the structure.
593  *
594  */
595 faim_export int aim_puttlv(u_char *dest, struct aim_tlv_t *newtlv)
596 {
597   int i=0;
598
599   dest[i++] = newtlv->type >> 8;
600   dest[i++] = newtlv->type & 0x00FF;
601   dest[i++] = newtlv->length >> 8;
602   dest[i++] = newtlv->length & 0x00FF;
603   memcpy(&(dest[i]), newtlv->value, newtlv->length);
604   i+=newtlv->length;
605   return i;
606 }
607
608 /**
609  * aim_createtlv - Generate an aim_tlv_t structure.
610  * 
611  * Allocates an empty TLV structure and returns a pointer
612  * to it; %NULL on error.
613  *
614  */
615 faim_export struct aim_tlv_t *aim_createtlv(void)
616 {
617   struct aim_tlv_t *newtlv;
618
619   if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t))))
620     return NULL;
621   memset(newtlv, 0, sizeof(struct aim_tlv_t));
622   return newtlv;
623 }
624
625 /**
626  * aim_freetlv - Free a aim_tlv_t structure
627  * @oldtlv: TLV to be destroyed
628  *
629  * Frees both the TLV structure and the value portion.
630  *
631  */
632 faim_export int aim_freetlv(struct aim_tlv_t **oldtlv)
633 {
634   if (!oldtlv)
635     return -1;
636   if (!*oldtlv)
637     return -1;
638   if ((*oldtlv)->value)
639     free((*oldtlv)->value);
640   free(*(oldtlv));
641   (*oldtlv) = NULL;
642
643   return 0;
644 }
645
646 /**
647  * aim_puttlv_8 - Write a one-byte TLV.
648  * @buf: Destination buffer
649  * @t: TLV type
650  * @v: Value
651  *
652  * Writes a TLV with a one-byte integer value portion.
653  *
654  */
655 faim_export int aim_puttlv_8(unsigned char *buf, unsigned short t, unsigned char  v)
656 {
657   int curbyte=0;
658
659   curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
660   curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0001);
661   curbyte += aimutil_put8(buf+curbyte, (unsigned char)(v&0xff));
662
663   return curbyte;
664 }
665
666 /**
667  * aim_puttlv_16 - Write a two-byte TLV.
668  * @buf: Destination buffer
669  * @t: TLV type
670  * @v: Value
671  *
672  * Writes a TLV with a two-byte integer value portion.
673  *
674  */
675 faim_export int aim_puttlv_16(u_char *buf, u_short t, u_short v)
676 {
677   int curbyte=0;
678   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
679   curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002);
680   curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff));
681   return curbyte;
682 }
683
684 /**
685  * aim_puttlv_32 - Write a four-byte TLV.
686  * @buf: Destination buffer
687  * @t: TLV type
688  * @v: Value
689  *
690  * Writes a TLV with a four-byte integer value portion.
691  *
692  */
693 faim_export int aim_puttlv_32(u_char *buf, u_short t, u_long v)
694 {
695   int curbyte=0;
696   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
697   curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004);
698   curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff));
699   return curbyte;
700 }
701
702 /**
703  * aim_puttlv_str - Write a string TLV.
704  * @buf: Destination buffer
705  * @t: TLV type
706  * @l: Length of string
707  * @v: String to write
708  *
709  * Writes a TLV with a string value portion.  (Only the first @l
710  * bytes of the passed string will be written, which should not
711  * include the terminating NULL.)
712  *
713  */
714 faim_export int aim_puttlv_str(u_char *buf, u_short t, int l, char *v)
715 {
716   int curbyte;
717   
718   curbyte  = 0;
719   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
720   curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff));
721   if (v)
722     memcpy(buf+curbyte, (unsigned char *)v, l);
723   curbyte += l;
724   return curbyte;
725 }
This page took 1.530873 seconds and 5 git commands to generate.