]> git.sur5r.net Git - openldap/blob - contrib/whois++/command.c
fixed test on "" (empty) parent dn
[openldap] / contrib / whois++ / command.c
1 #if !defined(lint)
2 static char copyright[] = "Copyright 1992 The University of Adelaide";
3 #endif
4
5 /*
6  *                      C O M M A N D
7  *
8  * Author:      Mark R. Prior
9  *              Communications and Systems Branch
10  *              Information Technology Division
11  *              The University of Adelaide
12  * E-mail:      mrp@itd.adelaide.edu.au
13  * Date:        October 1992
14  * Version:     1.8
15  * Description:
16  *              Interpret the command sent by the client
17  *
18  * Redistribution and use in source and binary forms are permitted
19  * provided that the above copyright notice and this paragraph are
20  * duplicated in all such forms and that any documentation,
21  * advertising materials, and other materials related to such
22  * distribution and use acknowledge that the software was developed
23  * by the University of Adelaide. The name of the University may not
24  * be used to endorse or promote products derived from this software
25  * without specific prior written permission.
26  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
28  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  */
30
31 #include "whois++.h"
32 #include <stdlib.h>
33 extern int getdtablesize (void);
34
35 #define isspecial(c)    ( (c) == ',' || (c) == ';' || (c) == ':' || (c) == '=' )
36
37 static  char    **component = NULL;
38 static  int     numberOfComponents;
39 static  int     components = 10;
40
41 static int
42 getToken( char *token )
43 {
44         static char     *buffer = NULL;
45         static int      idx;
46         char            ch;
47         fd_set          readfds;
48         struct timeval  timeout;
49         int             i, status, tablesize;
50
51         if ( buffer == NULL ) {
52                 tablesize = getdtablesize();
53
54 #ifdef FD_SETSIZE
55                 if ( tablesize > FD_SETSIZE ) {
56                         tablesize = FD_SETSIZE;
57                 }
58 #endif  /* FD_SETSIZE */
59
60                 timeout.tv_sec = 60;
61                 timeout.tv_usec = 0;
62                 FD_ZERO( &readfds );
63                 FD_SET( fileno( stdin ), &readfds );
64
65                 if ( (status = select( tablesize, &readfds, 0, 0, &timeout )) <= 0 ) {
66                         if ( status < 0 )
67                                 printFormatted( lineLength, TRUE, stdout,
68                                         "select: %s", strerror( errno ) );
69                         else
70                                 printFormatted( lineLength, TRUE, stdout,
71                                         "Connection timed out waiting for input." );
72                         exit( 1 );
73                 }
74 /**/            /*
75                  * We really should determine how many characters are
76                  * waiting for us and then malloc that amount rather than
77                  * just guessing!
78                  */
79                 if ( ( buffer = (char *)malloc(BUFSIZ) ) == NULL
80                         || fgets( buffer, BUFSIZ, stdin ) == NULL ) {
81                         *token = '\0';
82                         return EOF;
83                 }
84                 idx = 0;
85                 i = strlen( buffer );
86                 while ( i-- > 0 && ( buffer[i] == '\r' || buffer[i] == '\n' ) )
87                         buffer[i] = '\0';
88                 if ( log )
89                         syslog( LOG_INFO, "Whois++ Query: %s", buffer );
90         }
91         while ( buffer[idx] != '\0' && isspace( (unsigned char) buffer[idx] ) )
92                 idx++;
93         token[0] = buffer[idx++];
94         token[1] = '\0';
95         switch ( token[0] ) {
96         case '\0':
97                 strcpy( token, "<end of line>" );
98                 free( buffer );
99                 buffer = NULL;
100                 return EOF;
101
102         case '^':
103                 return TEMPLATE;
104
105         case '!':
106                 return HANDLE;
107
108         case '.':
109                 return ATTRIBUTE;
110
111         case '#':
112                 return VALUE;
113
114         case '*':
115                 return SEARCH_ALL;
116
117         case '?':
118                 return HELP;
119
120         case ':':
121                 return COLON;
122
123         case ';':
124                 return SEMICOLON;
125
126         case ',':
127                 return COMMA;
128
129         case '=':
130                 return EQUALS;
131
132         case '"':
133                 i = 0;
134                 do {
135                         ch = buffer[idx++];
136                         if ( ch == '\\' && buffer[idx] != '\0' )
137                                 token[i++] = buffer[idx++];
138                         else
139                                 token[i++] = ch;
140                 } while ( ch != '\0' && ch != '"' );
141                 if ( ch == '\0' ) {
142                         printFormatted( lineLength, TRUE, stdout,
143                                 "Trailing \" missing" );
144                         idx--;
145                 }
146                 token[--i] = '\0';
147                 return SEARCH;
148
149         default:
150                 i = 1;
151                 do {
152                         ch = buffer[idx++];
153                         if ( ch == '\\' && buffer[idx] != '\0' )
154                                 token[i++] = buffer[idx++];
155                         else
156                                 token[i++] = ch;
157                 } while ( ch != '\0' &&
158                           !isspace( (unsigned char) ch ) && !isspecial( ch ) );
159                 token[--i] = '\0';
160                 idx--;
161 /**/            /*
162                  * The following is a brute force lookup, once the names
163                  * have settled down this should change to a hash table,
164                  * or something similar.
165                  */
166                 if ( EQ( token, "help" ) )
167                         return HELP;
168                 else if ( EQ( token, "list" ) )
169                         return LIST;
170                 else if ( EQ( token, "show" ) )
171                         return SHOW;
172                 else if ( EQ( token, "constraints" ) )
173                         return CONSTRAINTS;
174                 else if ( EQ( token, "describe" ) )
175                         return DESCRIBE;
176                 else if ( EQ( token, "version" ) )
177                         return VERSION;
178                 else if ( EQ( token, "template" ) )
179                         return TEMPLATE;
180                 else if ( EQ( token, "handle" ) )
181                         return HANDLE;
182                 else if ( EQ( token, "attribute" ) )
183                         return ATTRIBUTE;
184                 else if ( EQ( token, "value" ) )
185                         return VALUE;
186                 else if ( EQ( token, "full" ) )
187                         return FULL;
188                 else if ( EQ( token, "abridged" ) )
189                         return ABRIDGED;
190                 else if ( EQ( token, "summary" ) )
191                         return SUMMARY;
192                 else if ( EQ( token, "format" ) )
193                         return FORMAT;
194                 else if ( EQ( token, "hold" ) )
195                         return HOLD;
196                 else if ( EQ( token, "maxhits" ) )
197                         return MAXHITS;
198                 else if ( EQ( token, "match" ) )
199                         return MATCH;
200                 else if ( EQ( token, "linelength" ) )
201                         return LINE_LENGTH;
202                 else if ( EQ( token, "command" ) )
203                         return COMMAND;
204                 else if ( EQ( token, "trace" ) )
205                         return TRACE;
206                 else
207                         return SEARCH;
208         }
209 }
210
211 static int
212 term(
213         int     token,
214         char    *value,
215         char    *attribute,
216         int     *specifier,
217         int     *soundex
218 )
219 {
220         char    buffer[BUFSIZ], temp[BUFSIZ];
221         int     iterations;
222
223         *soundex = FALSE;
224         switch ( token ) {
225         case ATTRIBUTE: /* . */
226         case VALUE:     /* # */
227         case HANDLE:    /* ! */
228         case TEMPLATE:  /* ^ */
229         case SEARCH_ALL:/* * */
230                 *specifier = token;
231                 if ( strlen( value ) > 1 ) {
232                         /* fullname used, so expect an equals sign */
233                         if ( getToken( buffer ) != EQUALS ) {
234                                 printFormatted( lineLength, TRUE, stdout,
235                                         "\"=\" expected" );
236                                 return ERROR;
237                         } else
238                                 token = getToken( value );
239                 } else 
240                         token = getToken( value );
241                 if ( token != COMMA && token != SEMICOLON && token != EQUALS
242                         && token != COLON && token != EOF ) {
243                         token = getToken( buffer );
244                         break;
245                 }
246
247         case COMMA:
248         case SEMICOLON:
249         case EQUALS:
250         case COLON:
251         case EOF:
252                 printFormatted( lineLength, TRUE, stdout,
253                         "Expected search string but got \"%s\"", buffer );
254                 return ERROR;
255
256         default:
257                 *specifier = SEARCH_ALL;
258                 if ( ( token = getToken( buffer ) ) == EQUALS ) {
259                         strcpy( attribute, value );
260                         token = getToken( value );
261                         if ( token == COMMA || token == SEMICOLON
262                                 || token == COLON || token == EOF ) {
263                                 printFormatted( lineLength, TRUE, stdout,
264                                         "Syntax error, string expected." );
265                                 return ERROR;
266                         }
267                         token = getToken( buffer );
268                 }
269         }
270
271         while ( token != COMMA && token != SEMICOLON && token != COLON
272                 && token != EOF ) {
273                 if ( *value != '\0' )
274                         strcat( value, " " );
275                 strcat( value, buffer );
276                 token = getToken( buffer );
277         }
278         iterations = 2;
279         while ( token == COMMA ) {
280                 token = getToken( buffer );
281                 switch ( token ) {
282                 case MATCH:
283                         iterations = 0;
284                         if ( ( token = getToken( buffer ) ) != EQUALS ) {
285                                 printFormatted( lineLength, TRUE, stdout,
286                                         "\"=\" expected" );
287                         } else
288                                 token = getToken( buffer );
289                         if ( EQ( buffer, "exact" ) )
290                                 *soundex = FALSE;
291                         else if ( EQ( buffer, "fuzzy" ) )
292                                 *soundex = TRUE;
293                         else
294                                 printFormatted( lineLength, TRUE, stdout,
295                                         "Unrecognised search type" );
296                         token = getToken( buffer );
297                         break;
298
299                 default:
300                         if ( iterations == 0 ) {
301                                 /* obviously an unrecognised constraint */
302                                 printFormatted( lineLength, TRUE, stdout,
303                                         "Constraint \"%s\" not supported",
304                                         buffer );
305                                 while ( ( token = getToken( buffer ) ) != EOF
306                                         && token != COMMA && token != COLON
307                                         && token != SEMICOLON )
308                                         ;
309                         } else {
310                                 strcpy( temp, buffer );
311                                 token = getToken( buffer );
312                                 if ( token == EQUALS ) {
313                                         iterations = 0;
314                                         printFormatted( lineLength, TRUE, stdout,
315                                                 "Constraint \"%s\" not supported",
316                                                 buffer );
317                                 }
318                                 while ( token != EOF && token != SEMICOLON
319                                         && token != COLON && token != COMMA ) {
320                                         if ( iterations > 0 ) {
321                                                 strcat( temp, " " );
322                                                 strcat( temp, buffer );
323                                         }
324                                         token = getToken( buffer );
325                                 }
326                                 if ( iterations > 0 ) {
327                                         printFormatted( lineLength, TRUE, stdout,
328                                                 "Assuming \"%s\" part of query and not an unrecognised constraint.", temp );
329                                         strcat( value, "," );
330                                         strcat( value, temp );
331                                 }
332                         }
333                         break;
334
335                 }
336                 iterations--;
337         }
338         if ( *value == '\0' ) {
339                 printFormatted( lineLength, TRUE, stdout,
340                         "Value not specified" );
341                 return ERROR;
342         }
343         if ( *specifier == NULL )
344                 *specifier = SEARCH_ALL;
345         return token;
346 }
347
348 static int
349 processTerm(
350         int     specifier,
351         int     soundex,
352         char    *buffer,
353         char    *attribute,
354         char    *value
355 )
356 {
357         char    *s, *t;
358         char    query[BUFSIZ];
359         char    **reallocResult;
360
361         switch ( specifier ) {
362         case SEARCH_ALL:
363                 if ( numberOfComponents+3 >= components ) {
364                         components += 10;
365                         reallocResult = (char **)realloc(component, sizeof(char **)*components);
366                         if ( reallocResult == NULL ) {
367                                 printFormatted( lineLength, TRUE, stdout,
368                                         "Realloc failed" );
369                                 return ERROR;
370                         } else
371                                 component = reallocResult;
372                 }
373                 if ( attribute != NULL && *attribute != '\0' ) {
374                         /* The user obviously knows what they are doing */
375                         sprintf( query, "(%s%s%s)", attribute,
376                                 (soundex)?"~=":"=", buffer );
377                 } else {
378                         if ( ( s = strchr( buffer, ',' ) ) != NULL ) {
379                                 *s++ = '\0';
380                                 while ( *s && isspace( (unsigned char) *s ) )
381                                         s++;
382                                 sprintf( query, "(sn%s%s)",
383                                         (soundex)?"~=":"=", buffer );
384                                 component[numberOfComponents++] = strdup( query );
385                                 /* let's just make sure there is no title */
386                                 if ( ( t = strrchr( s, ',' ) ) != NULL ) {
387                                         *t++ = '\0';
388                                         while ( *t && isspace( (unsigned char) *t ) )
389                                                 t++;
390                                         sprintf( query, "(personalTitle%s%s)",
391                                                 (soundex)?"~=":"=", t );
392                                         component[numberOfComponents++] = strdup( query );
393                                 }
394                                 sprintf( query, "%s %s", s, buffer );
395                                 strcpy( buffer, query );
396                         } else if ( strncasecmp( buffer, "first ", 6 ) == 0 ) {
397                                 sprintf( query, "%s *", &buffer[6] );
398                                 strcpy( buffer, query );
399                         }
400                         if ( ( s = strchr( buffer, '@' ) ) != NULL ) {
401                                 *s++ = '\0';
402                                 if ( *buffer == '\0' ) /* no username */
403                                         sprintf( query, "(mail=*@%s)", s );
404                                 else if ( *s == '\0' ) /* no host */
405                                         sprintf( query, "(|(mail=%s@*)(userid=%s))",
406                                                 buffer, buffer );
407                                 else
408                                         sprintf( query, "(mail=%s@%s)",
409                                                 buffer, s );
410                                 if ( soundex )
411                                         printFormatted( lineLength, TRUE, stdout,
412                                                 "Fuzzy matching not supported on e-mail address queries" );
413                         } else if ( strchr( buffer, ' ' ) == NULL ) {
414                                 sprintf( query,
415                                         "(|(sn%s%s)(userid%s%s)(l%s%s)(ou%s%s)\
416 (&(cn%s%s)(!(objectClass=person))))",
417                                         (soundex)?"~=":"=", buffer,
418                                         (soundex)?"~=":"=", buffer,
419                                         (soundex)?"~=":"=", buffer,
420                                         (soundex)?"~=":"=", buffer,
421                                         (soundex)?"~=":"=", buffer );
422                         } else {
423 #if defined(UOFA)
424                                 sprintf( query, "(|(l%s%s)(ou%s%s)(preferredName%s%s)",
425                                         (soundex)?"~=":"=", buffer,
426                                         (soundex)?"~=":"=", buffer,
427                                         (soundex)?"~=":"=", buffer );
428 #else
429                                 sprintf( query, "(|(l%s%s)(ou%s%s)",
430                                         (soundex)?"~=":"=", buffer,
431                                         (soundex)?"~=":"=", buffer );
432 #endif
433                                 /*
434                                  * If LDAP and/or Quipu didn't strip spaces
435                                  * then this would be different but as it does
436                                  * this is easy :-) but it also means we might
437                                  * get false hits.
438                                  */
439                                 if ( soundex ) {
440                                         strcat( query, "(cn~=" );
441                                         strcat( query, buffer );
442                                 } else {
443                                         strcat( query, "(cn=*" );
444                                         strcat( query, strtok( buffer, " " ) );
445                                         while ( ( s = strtok( NULL, " " ) ) != NULL ) {
446                                                 strcat( query, " * " );
447                                                 strcat( query, s );
448                                         }
449                                 }
450                                 strcat( query, "))" );
451                         }
452                 }
453                 component[numberOfComponents++] = strdup( query );
454                 break;
455
456         case ATTRIBUTE:
457                 if ( numberOfComponents+1 >= components ) {
458                         components += 10;
459                         reallocResult = (char **)realloc(component, sizeof(char **)*components);
460                         if ( reallocResult == NULL ) {
461                                 printFormatted( lineLength, TRUE, stdout,
462                                         "Realloc failed" );
463                                 return ERROR;
464                         } else
465                                 component = reallocResult;
466                 }
467                 if ( *value != '\0' ) {
468                         sprintf( query, "(%s%s%s)", buffer,
469                                 (soundex)?"~=":"=", value );
470                         component[numberOfComponents++] = strdup( query );
471                         *value = '\0';
472                 } else {
473                         if ( *attribute != '\0' ) {
474                                 sprintf( query, "(%s%s*)", attribute,
475                                         (soundex)?"~=":"=" );
476                                 component[numberOfComponents++] = strdup( query );
477                         }
478                         strcpy( attribute, buffer );
479                 }
480                 break;
481
482         case TEMPLATE:
483                 if ( numberOfComponents+1 >= components ) {
484                         components += 10;
485                         reallocResult = (char **)realloc(component, sizeof(char **)*components);
486                         if ( reallocResult == NULL ) {
487                                 printFormatted( lineLength, TRUE, stdout,
488                                         "Realloc failed" );
489                                 return ERROR;
490                         } else
491                                 component = reallocResult;
492                 }
493                 sprintf( query, "(objectClass%s%s)",
494                         (soundex)?"~=":"=", templateToObjectClass( buffer ) );
495                 component[numberOfComponents++] = strdup( query );
496                 break;
497
498         case VALUE:
499                 if ( *attribute != '\0' ) {
500                         if ( numberOfComponents+1 >= components ) {
501                                 components += 10;
502                                 reallocResult = (char **)realloc(component, sizeof(char **)*components);
503                                 if ( reallocResult == NULL ) {
504                                         printFormatted( lineLength, TRUE, stdout,
505                                                 "Realloc failed" );
506                                         return ERROR;
507                                 } else
508                                         component = reallocResult;
509                         }
510                         sprintf( query, "(%s%s%s)", attribute,
511                                 (soundex)?"~=":"=", buffer );
512                         component[numberOfComponents++] = strdup( query );
513                         *attribute = '\0';
514                 } else {
515                         if ( *value != '\0' )
516                                 printFormatted( lineLength, TRUE, stdout,
517                                         "Ignoring old value (%s)", value );
518                         strcpy( value, buffer );
519                 }
520                 break;
521
522         case HANDLE:
523                 if ( numberOfComponents+1 >= components ) {
524                         components += 10;
525                         reallocResult = (char **)realloc(component, sizeof(char **)*components);
526                         if ( reallocResult == NULL ) {
527                                 printFormatted( lineLength, TRUE, stdout,
528                                         "Realloc failed" );
529                                 return ERROR;
530                         } else
531                                 component = reallocResult;
532                 }
533                 component[numberOfComponents++] = strdup( buffer );
534                 return READ;
535
536         }
537         return SEARCH;
538 }
539
540 int
541 parseCommand( char *query )
542 {
543         /*
544          * This procedure reads the string sent by the user and breaks it
545          * down into command to execute.
546          */
547         char    buffer[BUFSIZ], attribute[BUFSIZ], objectClass[BUFSIZ],
548                 value[BUFSIZ];
549         char    **reallocResult;
550         int     command, specificName, length, token, i, j, specifier, soundex;
551         int     trace = FALSE;
552
553         switch ( command = getToken( buffer ) ) {
554         case COMMAND:
555         case CONSTRAINTS:
556         case DESCRIBE:
557         case VERSION:
558                 /* <command> */
559                 token = getToken( buffer );
560                 break;
561
562         case HELP:
563         case LIST:
564                 /* <command> [ <string> ] */
565                 if ( ( token = getToken( buffer ) ) != EOF && token != COLON ) {
566                         strcpy( query, buffer );
567                         token = getToken( buffer );
568                 } else
569                         *query = '\0';
570                 break;
571
572         case SHOW:
573                 /* "show" <string> */
574                 if ( ( token = getToken( buffer ) ) != EOF && token != COLON ) {
575                         strcpy( query, buffer );
576                         token = getToken( buffer );
577                 } else {
578                         printFormatted( lineLength, TRUE, stdout,
579                                 "Show must have a parameter" );
580                         return ERROR;
581                 }
582                 break;
583
584         default:
585                 /* <term> [ ";" <term> ] */
586                 *attribute = '\0';
587                 *value = '\0';
588                 soundex = FALSE;
589                 numberOfComponents = 0;
590                 if ( ( component = (char **)malloc(sizeof(char **)*components) ) == NULL ) {
591                         printFormatted( lineLength, TRUE, stdout,
592                                 "Malloc failed" );
593                         return ERROR;
594                 }
595                 if ( ( token = term( command, buffer, attribute, &specifier,
596                         &soundex ) ) != ERROR )
597                         command = processTerm( specifier, soundex, buffer,
598                                 attribute, value );
599                 else
600                         return ERROR;
601                 if ( token == SEMICOLON ) {
602                         if ( command == READ ) {
603                                 printFormatted( lineLength, TRUE, stdout,
604                                         "Multiple components on a Handle query not supported." );
605                                 return ERROR;
606                         }
607                         do {
608                                 soundex = FALSE;
609                                 token = getToken( buffer );
610                                 token = term( token, buffer, attribute,
611                                         &specifier, &soundex );
612                                 command = processTerm( specifier, soundex,
613                                         buffer, attribute, value );
614                                 if ( command == READ ) {
615                                         printFormatted( lineLength, TRUE, stdout,
616                                                 "Multiple components on a Handle query not supported." );
617                                         return ERROR;
618                                 } else if ( command == ERROR )
619                                         return ERROR;
620                         } while ( token == SEMICOLON );
621                 }
622                 /*
623                  * Need to tidy up outstanding single value or attribute terms
624                  */
625                 if ( *attribute != '\0' ) {
626                         if ( numberOfComponents+1 >= components ) {
627                                 components += 10;
628                                 reallocResult = (char **)realloc(component, sizeof(char **)*components);
629                                 if ( reallocResult == NULL ) {
630                                         printFormatted( lineLength, TRUE, stdout,
631                                                 "Realloc failed" );
632                                         return ERROR;
633                                 } else
634                                         component = reallocResult;
635                         }
636                         sprintf( query, "(%s%s*)", attribute,
637                                 (soundex)?"~=":"=" );
638                         component[numberOfComponents++] = strdup( query );
639                 }
640                 if ( *value != '\0' )
641                         if ( processTerm( SEARCH_ALL, soundex, value, NULL, NULL ) == ERROR )
642                                 return ERROR;
643                 if ( numberOfComponents == 0 ) {
644                         printFormatted( lineLength, TRUE, stdout,
645                                 "NULL query." );
646                         return ERROR;
647                 } else if ( numberOfComponents == 1 )
648                         strcpy( query, component[0] );
649                 else {
650                         strcpy( query, "(&" );
651                         for ( i = 0; i < numberOfComponents; i++ )
652                                 strcat( query, component[i] );
653                         strcat( query, ")" );
654                 }
655                 free( component );
656                 break;
657
658         }
659         if ( token == COLON ) { /* global constraints */
660                 do {
661                         token = getToken( buffer );
662                         switch ( token ) {
663                         case FORMAT:
664                                 if ( ( token = getToken( buffer ) ) != EQUALS ) {
665                                         printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
666                                 } else
667                                         token = getToken( buffer );
668                                 switch ( token ) {
669                                 case FULL:
670                                 case ABRIDGED:
671                                 case HANDLE:
672                                 case SUMMARY:
673                                         if ( outputFormat != NULL )
674                                                 printFormatted( lineLength, TRUE, stdout, "Only one response format can be specified." );
675                                         else
676                                                 outputFormat = token;
677                                         break;
678
679                                 default:
680                                         printFormatted( lineLength, TRUE, stdout, "Unrecognised format specifier" );
681                                 }
682                                 token = getToken( buffer );
683                                 break;
684
685                         case HOLD:
686                                 holdConnection = TRUE;
687                                 token = getToken( buffer );
688                                 break;
689
690                         case MAXHITS:
691                                 if ( ( token = getToken( buffer ) ) != EQUALS ) {
692                                         printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
693                                 } else
694                                         token = getToken( buffer );
695                                 if ( (maxHits = atoi( buffer )) < 1 
696                                         || maxHits > maximumSize ) {
697                                         printFormatted( lineLength, TRUE, stdout, "Invalid maxhits value, defaulting to %s", maximumSize );
698                                         maxHits = maximumSize;
699                                 }
700                                 token = getToken( buffer );
701                                 break;
702
703                         case LANGUAGE:
704                                 if ( ( token = getToken( buffer ) ) != EQUALS ) {
705                                         printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
706                                 } else
707                                         token = getToken( buffer );
708 /**/                            /* need to save this value and lookup locale */
709                                 printFormatted( lineLength, TRUE, stdout,
710                                         "Language not currently implemented" );
711                                 token = getToken( buffer );
712                                 break;
713
714                         case LINE_LENGTH:
715                                 if ( ( token = getToken( buffer ) ) != EQUALS ) {
716                                         printFormatted( lineLength, TRUE, stdout, "\"=\" expected" );
717                                 } else
718                                         token = getToken( buffer );
719                                 lineLength = atoi( buffer );
720                                 if ( lineLength < MIN_LINE_LENGTH
721                                         || lineLength > MAX_LINE_LENGTH ) {
722                                         printFormatted( lineLength, TRUE, stdout, "Invalid line length, using default %d", DEFAULT_LINE_LENGTH );
723                                         lineLength = DEFAULT_LINE_LENGTH;
724                                 }
725                                 token = getToken( buffer );
726                                 break;
727
728                         case TRACE:
729                                 trace = TRUE;
730                                 token = getToken( buffer );
731                                 break;
732
733                         default:
734                                 printFormatted( lineLength, TRUE, stdout, "Unrecognised global constraint \"%s\"", buffer );
735                                 while ( ( token = getToken( buffer ) ) != EOF
736                                         && token != COMMA )
737                                         ;
738                                 break;
739
740                         }
741                 } while ( token == COMMA );
742         }
743         if ( token != EOF ) {
744                 printFormatted( lineLength, TRUE, stdout,
745                         "Data following \"%s\" ignored.", buffer );
746                 while ( ( token = getToken( buffer ) ) != EOF )
747                         ;
748         }
749         if ( trace && ( command == READ || command == SEARCH ) )
750                 switch (command) {
751                 case READ:
752                         printFormatted( lineLength, TRUE, stdout,
753                                 "Attempting to read \"%s\"", query );
754                         break;
755
756                 case SEARCH:
757                         printFormatted( lineLength, TRUE, stdout,
758                                 "Searching using LDAP query %s", query );
759                         break;
760
761                 }
762         return command;
763 }