]> andersk Git - libfaim.git/blob - aim_tlv.c
- Sat Dec 2 02:14:45 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_writetlvchain - Write a TLV chain into a data buffer.
326  * @buf: Destination buffer
327  * @buflen: Maximum number of bytes that will be written to buffer
328  * @list: Source TLV chain
329  *
330  * Copies a TLV chain into a raw data buffer, writing only the number
331  * of bytes specified. This operation does not free the chain; 
332  * aim_freetlvchain() must still be called to free up the memory used
333  * by the chain structures.
334  *
335  */
336 faim_export int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list)
337 {
338   int goodbuflen = 0;
339   int i = 0;
340   struct aim_tlvlist_t *cur;
341
342   if (!list || !buf || !buflen)
343     return 0;
344
345   /* do an initial run to test total length */
346   for (cur = *list; cur; cur = cur->next) {
347     goodbuflen += 2 + 2; /* type + len */
348     goodbuflen += cur->tlv->length;
349   }
350
351   if (goodbuflen > buflen)
352     return 0; /* not enough buffer */
353
354   /* do the real write-out */
355   for (cur = *list; cur; cur = cur->next) {
356     i += aimutil_put16(buf+i, cur->tlv->type);
357     i += aimutil_put16(buf+i, cur->tlv->length);
358     memcpy(buf+i, cur->tlv->value, cur->tlv->length);
359     i += cur->tlv->length;
360   }
361
362   return i;
363 }
364
365
366 /**
367  * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
368  * @list: Source chain
369  * @type: Requested TLV type
370  * @nth: Index of TLV of type to get
371  *
372  * Returns a pointer to an aim_tlv_t of the specified type; 
373  * %NULL on error.  The @nth parameter is specified starting at %1.
374  * In most cases, there will be no more than one TLV of any type
375  * in a chain.
376  *
377  */
378 faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
379 {
380   int i;
381   struct aim_tlvlist_t *cur;
382   
383   i = 0;
384   for (cur = list; cur != NULL; cur = cur->next)
385     {
386       if (cur && cur->tlv)
387         {
388           if (cur->tlv->type == type)
389             i++;
390           if (i >= nth)
391             return cur->tlv;
392         }
393     }
394   return NULL;
395 }
396
397 /**
398  * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
399  * @list: Source TLV chain
400  * @type: TLV type to search for
401  * @nth: Index of TLV to return
402  *
403  * Same as aim_gettlv(), except that the return value is a %NULL-
404  * terminated string instead of an aim_tlv_t.  This is a 
405  * dynamic buffer and must be freed by the caller.
406  *
407  */
408 faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
409 {
410   struct aim_tlv_t *tlv;
411   char *newstr;
412
413   if (!(tlv = aim_gettlv(list, type, nth)))
414     return NULL;
415   
416   newstr = (char *) malloc(tlv->length + 1);
417   memcpy(newstr, tlv->value, tlv->length);
418   *(newstr + tlv->length) = '\0';
419
420   return newstr;
421 }
422
423 /**
424  * aim_grabtlv - Grab a single TLV from a data buffer
425  * @src: Source data buffer (must be at least 4 bytes long)
426  *
427  * Creates a TLV structure aim_tlv_t and returns it
428  * filled with values from a buffer, possibly including a 
429  * dynamically allocated buffer for the value portion.
430  *
431  * Both the aim_tlv_t and the tlv->value pointer
432  * must be freed by the caller if non-%NULL.
433  *
434  */
435 faim_export struct aim_tlv_t *aim_grabtlv(u_char *src)
436 {
437   struct aim_tlv_t *dest = NULL;
438
439   dest = aim_createtlv();
440
441   dest->type = src[0] << 8;
442   dest->type += src[1];
443
444   dest->length = src[2] << 8;
445   dest->length += src[3];
446
447   dest->value = (u_char *) malloc(dest->length*sizeof(u_char));
448   memset(dest->value, 0, dest->length*sizeof(u_char));
449
450   memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
451   
452   return dest;
453 }
454
455 /**
456  * aim_grabtlvstr - Grab a single TLV from a data buffer as string
457  * @src: Source data buffer (must be at least 4 bytes long)
458  *
459  * Creates a TLV structure aim_tlv_t and returns it
460  * filled with values from a buffer, possibly including a 
461  * dynamically allocated buffer for the value portion, which 
462  * is %NULL-terminated as a string.
463  *
464  * Both the aim_tlv_t and the tlv->value pointer
465  * must be freed by the caller if non-%NULL.
466  *
467  */
468 faim_export struct aim_tlv_t *aim_grabtlvstr(u_char *src)
469 {
470   struct aim_tlv_t *dest = NULL;
471
472   dest = aim_createtlv();
473
474   dest->type = src[0] << 8;
475   dest->type += src[1];
476
477   dest->length = src[2] << 8;
478   dest->length += src[3];
479
480   dest->value = (u_char *) malloc((dest->length+1)*sizeof(u_char));
481   memset(dest->value, 0, (dest->length+1)*sizeof(u_char));
482
483   memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
484   dest->value[dest->length] = '\0';
485
486   return dest;
487 }
488
489 /**
490  * aim_puttlv - Write a aim_tlv_t into a data buffer
491  * @dest: Destination data buffer
492  * @newtlv: Source TLV structure
493  *
494  * Writes out the passed TLV structure into the buffer. No bounds
495  * checking is done on the output buffer.
496  *
497  * The passed aim_tlv_t is not freed. aim_freetlv() should
498  * still be called by the caller to free the structure.
499  *
500  */
501 faim_export int aim_puttlv(u_char *dest, struct aim_tlv_t *newtlv)
502 {
503   int i=0;
504
505   dest[i++] = newtlv->type >> 8;
506   dest[i++] = newtlv->type & 0x00FF;
507   dest[i++] = newtlv->length >> 8;
508   dest[i++] = newtlv->length & 0x00FF;
509   memcpy(&(dest[i]), newtlv->value, newtlv->length);
510   i+=newtlv->length;
511   return i;
512 }
513
514 /**
515  * aim_createtlv - Generate an aim_tlv_t structure.
516  * 
517  * Allocates an empty TLV structure and returns a pointer
518  * to it; %NULL on error.
519  *
520  */
521 faim_export struct aim_tlv_t *aim_createtlv(void)
522 {
523   struct aim_tlv_t *newtlv;
524
525   if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t))))
526     return NULL;
527   memset(newtlv, 0, sizeof(struct aim_tlv_t));
528   return newtlv;
529 }
530
531 /**
532  * aim_freetlv - Free a aim_tlv_t structure
533  * @oldtlv: TLV to be destroyed
534  *
535  * Frees both the TLV structure and the value portion.
536  *
537  */
538 faim_export int aim_freetlv(struct aim_tlv_t **oldtlv)
539 {
540   if (!oldtlv)
541     return -1;
542   if (!*oldtlv)
543     return -1;
544   if ((*oldtlv)->value)
545     free((*oldtlv)->value);
546   free(*(oldtlv));
547   (*oldtlv) = NULL;
548
549   return 0;
550 }
551
552 /**
553  * aim_puttlv_16 - Write a two-byte TLV.
554  * @buf: Destination buffer
555  * @t: TLV type
556  * @v: Value
557  *
558  * Writes a TLV with a two-byte integer value portion.
559  *
560  */
561 faim_export int aim_puttlv_16(u_char *buf, u_short t, u_short v)
562 {
563   int curbyte=0;
564   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
565   curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002);
566   curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff));
567   return curbyte;
568 }
569
570 /**
571  * aim_puttlv_32 - Write a four-byte TLV.
572  * @buf: Destination buffer
573  * @t: TLV type
574  * @v: Value
575  *
576  * Writes a TLV with a four-byte integer value portion.
577  *
578  */
579 faim_export int aim_puttlv_32(u_char *buf, u_short t, u_long v)
580 {
581   int curbyte=0;
582   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
583   curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004);
584   curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff));
585   return curbyte;
586 }
587
588 /**
589  * aim_puttlv_str - Write a string TLV.
590  * @buf: Destination buffer
591  * @t: TLV type
592  * @l: Length of string
593  * @v: String to write
594  *
595  * Writes a TLV with a string value portion.  (Only the first @l
596  * bytes of the passed string will be written, which should not
597  * include the terminating NULL.)
598  *
599  */
600 faim_export int aim_puttlv_str(u_char *buf, u_short t, int l, char *v)
601 {
602   int curbyte;
603   
604   curbyte  = 0;
605   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
606   curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff));
607   if (v)
608     memcpy(buf+curbyte, (unsigned char *)v, l);
609   curbyte += l;
610   return curbyte;
611 }
This page took 0.091584 seconds and 5 git commands to generate.