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