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