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