]> git.deb.at Git - pkg/abook.git/blob - ldif.c
Imported Upstream version 0.5.3
[pkg/abook.git] / ldif.c
1
2 /*
3  * adapted to use with abook by JH <jheinonen@users.sourceforge.net>
4  */
5
6 /*
7  *
8  * Copyright (c) 1992-1996 Regents of the University of Michigan.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms are permitted
12  * provided that this notice is preserved and that due credit is given
13  * to the University of Michigan at Ann Arbor. The name of the University
14  * may not be used to endorse or promote products derived from this
15  * software without specific prior written permission. This software
16  * is provided ``as is'' without express or implied warranty.
17  *
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include "ldif.h"
27
28 #define ISSPACE(c) isspace((unsigned char)c)
29
30 #define LDAP_DEBUG_PARSE        0x800
31 #define LDAP_DEBUG_ANY          0xffff
32 #define LDIF_LINE_WIDTH         76      /* maximum length of LDIF lines */
33 #define LDIF_BASE64_LEN(vlen)   (((vlen) * 4 / 3 ) + 3)
34
35 #define LDIF_SIZE_NEEDED(tlen,vlen) \
36         ((tlen) + 4 + LDIF_BASE64_LEN(vlen) \
37      + ((LDIF_BASE64_LEN(vlen) + tlen + 3) / LDIF_LINE_WIDTH * 2 ))
38
39
40 #define Debug( level, fmt, arg1, arg2, arg3 )
41
42 #define RIGHT2                  0x03
43 #define RIGHT4                  0x0f
44 #define CONTINUED_LINE_MARKER   '\001'
45
46 static char nib2b64[0x40f] =
47         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
48
49 static unsigned char b642nib[0x80] = {
50         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55         0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
56         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
57         0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58         0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
59         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
60         0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
61         0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
62         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
63         0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
64         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
65         0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
66 };
67
68 /*
69  * str_parse_line - takes a line of the form "type:[:] value" and splits it
70  * into components "type" and "value".  if a double colon separates type from
71  * value, then value is encoded in base 64, and parse_line un-decodes it
72  * (in place) before returning.
73  */
74
75 int
76 str_parse_line(
77     char        *line,
78     char        **type,
79     char        **value,
80     int         *vlen
81 )
82 {
83         char    *p, *s, *d, *byte, *stop;
84         char    nib;
85         int     i, b64;
86
87         /* skip any leading space */
88         while ( ISSPACE( *line ) ) {
89                 line++;
90         }
91         *type = line;
92
93         for ( s = line; *s && *s != ':'; s++ )
94                 ;       /* NULL */
95         if ( *s == '\0' ) {
96                 Debug( LDAP_DEBUG_PARSE, "parse_line missing ':'\n", 0, 0, 0 );
97                 return( -1 );
98         }
99
100         /* trim any space between type and : */
101         for ( p = s - 1; p > line && ISSPACE( *p ); p-- ) {
102                 *p = '\0';
103         }
104         *s++ = '\0';
105
106         /* check for double : - indicates base 64 encoded value */
107         if ( *s == ':' ) {
108                 s++;
109                 b64 = 1;
110
111         /* single : - normally encoded value */
112         } else {
113                 b64 = 0;
114         }
115
116         /* skip space between : and value */
117         while ( ISSPACE( *s ) ) {
118                 s++;
119         }
120
121         /* if no value is present, error out */
122         if ( *s == '\0' ) {
123                 Debug( LDAP_DEBUG_PARSE, "parse_line missing value\n", 0,0,0 );
124                 return( -1 );
125         }
126
127         /* check for continued line markers that should be deleted */
128         for ( p = s, d = s; *p; p++ ) {
129                 if ( *p != CONTINUED_LINE_MARKER )
130                         *d++ = *p;
131         }
132         *d = '\0';
133
134         *value = s;
135         if ( b64 ) {
136                 stop = strchr( s, '\0' );
137                 byte = s;
138                 for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
139                         for ( i = 0; i < 3; i++ ) {
140                                 if ( p[i] != '=' && (p[i] & 0x80 ||
141                                     b642nib[ p[i] & 0x7f ] > 0x3f) ) {
142                                         Debug( LDAP_DEBUG_ANY,
143                                     "invalid base 64 encoding char (%c) 0x%x\n",
144                                             p[i], p[i], 0 );
145                                         return( -1 );
146                                 }
147                         }
148
149                         /* first digit */
150                         nib = b642nib[ p[0] & 0x7f ];
151                         byte[0] = nib << 2;
152                         /* second digit */
153                         nib = b642nib[ p[1] & 0x7f ];
154                         byte[0] |= nib >> 4;
155                         byte[1] = (nib & RIGHT4) << 4;
156                         /* third digit */
157                         if ( p[2] == '=' ) {
158                                 *vlen += 1;
159                                 break;
160                         }
161                         nib = b642nib[ p[2] & 0x7f ];
162                         byte[1] |= nib >> 2;
163                         byte[2] = (nib & RIGHT2) << 6;
164                         /* fourth digit */
165                         if ( p[3] == '=' ) {
166                                 *vlen += 2;
167                                 break;
168                         }
169                         nib = b642nib[ p[3] & 0x7f ];
170                         byte[2] |= nib;
171
172                         byte += 3;
173                 }
174                 s[ *vlen ] = '\0';
175         } else {
176                 *vlen = (int) (d - s);
177         }
178
179         return( 0 );
180 }
181
182 #if 0
183
184 /*
185  * str_getline - return the next "line" (minus newline) of input from a
186  * string buffer of lines separated by newlines, terminated by \n\n
187  * or \0.  this routine handles continued lines, bundling them into
188  * a single big line before returning.  if a line begins with a white
189  * space character, it is a continuation of the previous line. the white
190  * space character (nb: only one char), and preceeding newline are changed
191  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
192  * str_parse_line() routine above.
193  *
194  * it takes a pointer to a pointer to the buffer on the first call,
195  * which it updates and must be supplied on subsequent calls.
196  */
197
198 char *
199 str_getline( char **next )
200 {
201         char    *l;
202         char    c;
203
204         if ( *next == NULL || **next == '\n' || **next == '\0' ) {
205                 return( NULL );
206         }
207
208         l = *next;
209         while ( (*next = strchr( *next, '\n' )) != NULL ) {
210                 c = *(*next + 1);
211                 if ( ISSPACE( c ) && c != '\n' ) {
212                         **next = CONTINUED_LINE_MARKER;
213                         *(*next+1) = CONTINUED_LINE_MARKER;
214                 } else {
215                         *(*next)++ = '\0';
216                         break;
217                 }
218                 (*next)++;
219         }
220
221         return( l );
222 }
223
224 #endif
225
226 void
227 put_type_and_value( char **out, char *t, char *val, int vlen )
228 {
229         unsigned char   *byte, *p, *stop;
230         unsigned char   buf[3];
231         unsigned long   bits;
232         char            *save;
233         int             i, b64, pad, len, savelen;
234         len = 0;
235
236         /* put the type + ": " */
237         for ( p = (unsigned char *) t; *p; p++, len++ ) {
238                 *(*out)++ = *p;
239         }
240         *(*out)++ = ':';
241         len++;
242         save = *out;
243         savelen = len;
244         *(*out)++ = ' ';
245         b64 = 0;
246
247         stop = (unsigned char *) (val + vlen);
248         if ( isascii( val[0] ) && (ISSPACE( val[0] ) || val[0] == ':') ) {
249                 b64 = 1;
250         } else {
251                 for ( byte = (unsigned char *) val; byte < stop;
252                     byte++, len++ ) {
253                         if ( !isascii( *byte ) || !isprint( *byte ) ) {
254                                 b64 = 1;
255                                 break;
256                         }
257                         if ( len > LDIF_LINE_WIDTH ) {
258                                 *(*out)++ = '\n';
259                                 *(*out)++ = ' ';
260                                 len = 1;
261                         }
262                         *(*out)++ = *byte;
263                 }
264         }
265         if ( b64 ) {
266                 *out = save;
267                 *(*out)++ = ':';
268                 *(*out)++ = ' ';
269                 len = savelen + 2;
270                 /* convert to base 64 (3 bytes => 4 base 64 digits) */
271                 for ( byte = (unsigned char *) val; byte < stop - 2;
272                     byte += 3 ) {
273                         bits = (byte[0] & 0xff) << 16;
274                         bits |= (byte[1] & 0xff) << 8;
275                         bits |= (byte[2] & 0xff);
276
277                         for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
278                                 if ( len > LDIF_LINE_WIDTH ) {
279                                         *(*out)++ = '\n';
280                                         *(*out)++ = ' ';
281                                         len = 1;
282                                 }
283
284                                 /* get b64 digit from high order 6 bits */
285                                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
286                         }
287                 }
288
289                 /* add padding if necessary */
290                 if ( byte < stop ) {
291                         for ( i = 0; byte + i < stop; i++ ) {
292                                 buf[i] = byte[i];
293                         }
294                         for ( pad = 0; i < 3; i++, pad++ ) {
295                                 buf[i] = '\0';
296                         }
297                         byte = buf;
298                         bits = (byte[0] & 0xff) << 16;
299                         bits |= (byte[1] & 0xff) << 8;
300                         bits |= (byte[2] & 0xff);
301
302                         for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
303                                 if ( len > LDIF_LINE_WIDTH ) {
304                                         *(*out)++ = '\n';
305                                         *(*out)++ = ' ';
306                                         len = 1;
307                                 }
308
309                                 /* get b64 digit from low order 6 bits */
310                                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
311                         }
312
313                         for ( ; pad > 0; pad-- ) {
314                                 *(*out - pad) = '=';
315                         }
316                 }
317         }
318         *(*out)++ = '\n';
319 }
320
321
322 char *
323 ldif_type_and_value( char *type, char *val, int vlen )
324 /*
325  * return malloc'd, zero-terminated LDIF line
326  */
327 {
328     char        *buf, *p;
329     int         tlen;
330     size_t      bufsize, t;
331
332     tlen = strlen( type );
333
334     t = LDIF_SIZE_NEEDED( tlen, vlen );
335     if((bufsize = t + 1) <= t)
336         return NULL;
337
338     if (( buf = (char *)malloc( bufsize )) == NULL ) {
339         return NULL;
340     }
341
342     p = buf;
343     put_type_and_value( &p, type, val, vlen );
344     *p = '\0';
345
346     return( buf );
347 }
348