1    | /***************************************
2    |   $Revision: 1.31 $
3    | 
4    |   Query command module (qc).  This is what the whois query gets stored as in
5    |   memory.
6    | 
7    |   Status: NOT REVUED, TESTED
8    | 
9    |   ******************/ /******************
10   |   Filename            : query_command.c
11   |   Authors             : ottrey@ripe.net
12   |                         marek@ripe.net
13   |   ******************/ /******************
14   |   Copyright (c) 1999                              RIPE NCC
15   |  
16   |   All Rights Reserved
17   |   
18   |   Permission to use, copy, modify, and distribute this software and its
19   |   documentation for any purpose and without fee is hereby granted,
20   |   provided that the above copyright notice appear in all copies and that
21   |   both that copyright notice and this permission notice appear in
22   |   supporting documentation, and that the name of the author not be
23   |   used in advertising or publicity pertaining to distribution of the
24   |   software without specific, written prior permission.
25   |   
26   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32   |   ***************************************/
33   | #include <stdlib.h>
34   | #include <stdio.h>
35   | #include <string.h>
36   | #include <ctype.h>
37   | 
38   | #define QC_IMPL
39   | 
40   | #include "query_command.h"
41   | #include "defs.h"
42   | #include "constants.h"
43   | #include "which_keytypes.h"
44   | #include "memwrap.h"
45   | 
46   | #define MAX_OPT_ARG_C 20
47   | 
48   | /*+ String sizes +*/
49   | #define STR_S   63
50   | #define STR_M   255
51   | #define STR_L   1023
52   | #define STR_XL  4095
53   | #define STR_XXL 16383
54   | 
55   | #ifdef HAVE_STRSEP
56   | /* good */
57   | #else 
58   | #  if defined(HAVE_STRTOK_R) && !defined(HAVE_STRSEP)
59   | /* emulate strsep with strtok_r 
60   |    by making first arg to strtok_r point to the last 
61   | */
62   | char *
63   | strsep(char **stringp, const char *delim)
64   | {
65   |   return strtok_r( *stringp, delim, stringp);
66   | }
67   | #  else
68   | #  error "must have strsep or strtok_r"
69   | #  endif
70   | #endif
71   | 
72   | 
73   | /* my_getopt() */
74   | /*++++++++++++++++++++++++++++++++++++++
75   |   A thread safe version of getopt, used to get the options from the whois
76   |   query.
77   | 
78   |   int opt_argc The number of query arguments.
79   |   
80   |   char **opt_argv The query arguments.
81   |   
82   |   char *optstring The string containing valid options.
83   |   
84   |   int *my_optind_ptr A pointer to the index into the options of the option
85   |   returned.
86   |   
87   |   char **my_optarg_ptr A pointer to the arguments to be returned.
88   |    
89   |   More:
90   |   +html+ <PRE>
91   |   Authors:
92   |         ottrey
93   |   +html+ </PRE><DL COMPACT>
94   |   +html+ <DT>Online References:
95   |   +html+ <DD><UL>
96   |   +html+     <LI>man getopt
97   |   +html+ </UL></DL>
98   | 
99   |   ++++++++++++++++++++++++++++++++++++++*/
100  | static int my_getopt(int opt_argc, char **opt_argv, char *optstring, int *my_optind_ptr, char **my_optarg_ptr) {
101  |   int c='?';
102  |   int i, j;
103  |   int no_options;
104  |   int optind = *my_optind_ptr;
105  |   char option[4];
106  |   int option_matched=0;
107  |   
108  |   /* Get the number of options in the option string */
109  |   for(i=0, no_options=0; i < strlen(optstring) ; i++) {
110  |     if (optstring[i] != ':') {
111  |       no_options++;
112  |     }
113  |   }
114  | 
115  |   /* Iterate through all the option until it matches the current opt_argv */
116  |   /* Ie. opt_argv[optind] */
117  |   for (i=0, j=0; i <= no_options; i++, j++) {
118  |     /* Construct one option from the optstring */
119  |     option[0] = '-';
120  |     if (optstring[j] == ':') {
121  |       j++;
122  |     }
123  |     option[1] = optstring[j];
124  |     if ( optstring[j+1] == ':' ) {
125  |       option[2] = ':';
126  |     }
127  |     else {
128  |       option[2] = '\0';
129  |     }
130  |     option[3] = '\0';
131  | 
132  |     if (optind < opt_argc) {
133  |       if (strlen(opt_argv[optind]) > 0) {
134  |         
135  | 	  /*	  printf("opt_argv[%d] == option <==> %s == %s\n", 
136  | 		  optind, opt_argv[optind], option); */
137  |         
138  |         if (strncmp(opt_argv[optind], option, 2) == 0) {
139  |           /* Does the option have arguments. */
140  |           if (option[2] == ':') {
141  |             /* If the option has arguments */
142  |             if (strlen(opt_argv[optind]) > 2) {
143  |               /* If the arguments are in this token */
144  |               *my_optarg_ptr = (opt_argv[optind])+2;
145  |             }
146  |             else {
147  |               /* If the arguments are in the next token */
148  |               *my_optarg_ptr = opt_argv[optind+1];
149  |               optind++;
150  |             }
151  |           }
152  |           else {
153  |             /* There are no arguments to this token */
154  |             *my_optarg_ptr = NULL;
155  |           }
156  |           /* Option matched - break out of the search */
157  |           option_matched = 1;
158  |           break;
159  |         }
160  |       }
161  |     }
162  |   } /* for() */
163  |   
164  |   if ( option_matched == 1 ) {
165  |     /* This option was matched, return it. */
166  |     c = option[1];
167  | 
168  |     /* Move to the next opt_argv */
169  |     optind++;
170  |     *my_optind_ptr = optind;
171  |   }
172  |   else {
173  |     /* Discontinue search */
174  |     c = EOF;
175  |   }
176  | 
177  |   return c;
178  | 
179  | } /* my_getopt() */
180  | 
181  | /* QC_environ_to_string() */
182  | /*++++++++++++++++++++++++++++++++++++++
183  |   Convert the query_environ to a string.
184  | 
185  |   Query_environ *query_environ The query_environ to be converted.
186  |    
187  |   More:
188  |   +html+ <PRE>
189  |   Authors:
190  |         ottrey
191  |   +html+ </PRE><DL COMPACT>
192  |   +html+ <DT>Online References:
193  |   +html+ <DD><UL>
194  |   +html+ </UL></DL>
195  | 
196  |   ++++++++++++++++++++++++++++++++++++++*/
197  | char *QC_environ_to_string(Query_environ qe) {
198  |   char *result;
199  |   char *str1;
200  |   char str2[IP_ADDRSTR_MAX];
201  |   char result_buf[STR_XL];
202  | 
203  |   str1 = CO_sources_list_to_string(qe.sources_list);
204  |   
205  |   if( IP_addr_b2a( &(qe.pIP), str2, IP_ADDRSTR_MAX) != IP_OK ) { 
206  |     *str2 = '\0';
207  |   }
208  |   
209  |   sprintf(result_buf, "host=%s, keep_connection=%s, sources=%s, version=%s%s%s", qe.condat.ip, 
210  |           qe.k?"on":"off", 
211  |           str1, 
212  |           (qe.version == NULL) ? "?" : qe.version,
213  |           *str2 == '\0' ? "" : ", passedIP=",
214  |           *str2 == '\0' ? "" : str2
215  |           );
216  |   
217  |   wr_free(str1);
218  | 
219  |   dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);  
220  | 
221  |   strcpy(result, result_buf);
222  |   
223  |   return result;
224  |   
225  | } /* QC_environ_to_string() */
226  | 
227  | /* QC_query_command_to_string() */
228  | /*++++++++++++++++++++++++++++++++++++++
229  |   Convert the query_command to a string.
230  | 
231  |   Query_command *query_command The query_command to be converted.
232  |    
233  |   More:
234  |   +html+ <PRE>
235  |   Authors:
236  |         ottrey
237  |   +html+ </PRE><DL COMPACT>
238  |   +html+ <DT>Online References:
239  |   +html+ <DD><UL>
240  |   +html+ </UL></DL>
241  | 
242  |   ++++++++++++++++++++++++++++++++++++++*/
243  | char *QC_query_command_to_string(Query_command *query_command) {
244  |   char *result;
245  |   char result_buf[STR_XL];
246  |   char *str1;
247  |   char *str2;
248  |   char *str3;
249  | 
250  |   str1 = MA_to_string(query_command->inv_attrs_bitmap, DF_get_attribute_names());
251  |   str2 = MA_to_string(query_command->object_type_bitmap, DF_get_class_names());
252  |   str3 = WK_to_string(query_command->keytypes_bitmap);
253  |   
254  |   sprintf(result_buf, "Query_command : inv_attrs=%s, recursive=%s, object_type=%s, (e=%d,g=%d,l=%d,m=%d,q=%d,t=%d,v=%d,x=%d,F=%d,K=%d,L=%d,M=%d,R=%d,S=%d), possible keytypes=%s, keys=[%s]",
255  |           str1,
256  | 	  query_command->recursive?"y":"n",
257  |           str2,
258  |           query_command->e,
259  |           query_command->g,
260  |           query_command->l,
261  |           query_command->m,
262  |           query_command->q,
263  |           query_command->t,
264  |           query_command->v,
265  |           query_command->x,
266  |           query_command->fast,
267  |           query_command->filtered,
268  |           query_command->L,
269  |           query_command->M,
270  |           query_command->R,
271  |           query_command->S,
272  |           str3,
273  |           query_command->keys);
274  |   wr_free(str1);
275  |   wr_free(str2);
276  |   wr_free(str3);
277  | 
278  |   dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);  
279  |   strcpy(result, result_buf);
280  | 
281  |   return result;
282  |   
283  | } /* QC_query_command_to_string() */
284  | 
285  | /* log_command() */
286  | /*++++++++++++++++++++++++++++++++++++++
287  |   Log the command.
288  |   This is more to do with Tracing.  And should/will get merged with a tracing
289  |   module (when it is finalized.)
290  | 
291  |   char *query_str
292  |   
293  |   Query_command *query_command
294  |    
295  |   More:
296  |   +html+ <PRE>
297  |   Authors:
298  |         ottrey
299  |   +html+ </PRE><DL COMPACT>
300  |   +html+ <DT>Online References:
301  |   +html+ <DD><UL>
302  |   +html+ </UL></DL>
303  | 
304  |   ++++++++++++++++++++++++++++++++++++++*/
305  | static void log_command(char *query_str, Query_command *query_command) {
306  |   char *str;
307  | 
308  |   if( ER_is_traced(FAC_QC, ASP_QC_BUILD) ) {
309  |     str = QC_query_command_to_string(query_command);
310  |     ER_dbg_va(FAC_QC, ASP_QC_BUILD,
311  | 	      "query=[%s]   %s", query_str, str);
312  |     wr_free(str);
313  |   }
314  | } /* log_command() */
315  | 
316  | /* QC_environ_free() */
317  | /*++++++++++++++++++++++++++++++++++++++
318  |   Free the query_environ.
319  | 
320  |   Query_command *qc query_environ to be freed.
321  | 
322  |   More:
323  |   +html+ <PRE>
324  |   Authors:
325  |         ottrey
326  |   +html+ </PRE><DL COMPACT>
327  |   +html+ <DT>Online References:
328  |   +html+ <DD><UL>
329  |   +html+ </UL></DL>
330  | 
331  |   ++++++++++++++++++++++++++++++++++++++*/
332  | void QC_environ_free(Query_environ *qe) {
333  |   if (qe != NULL) {
334  |     if (qe->version != NULL) {
335  |       wr_free(qe->version);
336  |     }
337  | 
338  |     if (qe->sources_list != NULL) {
339  |       g_list_free(qe->sources_list);
340  |     }
341  |     wr_free(qe);
342  |   }
343  | } /* QC_environ_free() */
344  | 
345  | /* QC_free() */
346  | /*++++++++++++++++++++++++++++++++++++++
347  |   Free the query_command.
348  | 
349  |   Query_command *qc query_command to be freed.
350  | 
351  |   XXX I'm not sure the bitmaps will get freed.
352  |   qc->inv_attrs_bitmap
353  |   qc->object_type_bitmap
354  |   qc->keytypes_bitmap
355  | 
356  |   More:
357  |   +html+ <PRE>
358  |   Authors:
359  |         ottrey
360  |   +html+ </PRE><DL COMPACT>
361  |   +html+ <DT>Online References:
362  |   +html+ <DD><UL>
363  |   +html+ </UL></DL>
364  | 
365  |   ++++++++++++++++++++++++++++++++++++++*/
366  | void QC_free(Query_command *qc) {
367  |   if (qc != NULL) {
368  |     if (qc->keys != NULL) {
369  |       wr_free(qc->keys);
370  |     }
371  |     wr_free(qc);
372  |   }
373  | } /* QC_free() */
374  | 
375  | 
376  | 
377  | /* QC_fill() */
378  | /*++++++++++++++++++++++++++++++++++++++
379  |   Create a new query_command.
380  | 
381  |   
382  |   
383  |   char *query_str The garden variety whois query string.
384  | 
385  |   Query_environ *qe the environment
386  | 
387  |   Pre-condition: 
388  | 
389  |   Returns -1 when query incorrect, 0 otherwise
390  | 
391  |   More:
392  |   +html+ <PRE>
393  |   Authors:
394  |         ottrey
395  |   +html+ </PRE><DL COMPACT>
396  |   +html+ <DT>Online References:
397  |   +html+ <DD><UL>
398  |   +html+ </UL></DL>
399  | 
400  |   ++++++++++++++++++++++++++++++++++++++*/
401  | static
402  | int QC_fill(char *query_str, 
403  | 	     Query_command *query_command,
404  | 	     Query_environ *qe) {
405  |   char *my_optarg;
406  |   int my_optind = 0;
407  |   int c;
408  |   int errflg = 0;
409  |   char *inv_attrs_str = NULL;
410  |   char *object_types_str = NULL;
411  |   char *sources_str = NULL;
412  |   int opt_argc;
413  |   gchar **opt_argv;
414  |   char *value;
415  |   char *tmp_query_str;
416  |   int key_length;
417  |   int i;
418  |   int index;
419  |   int type;
420  |   int attr;
421  | 
422  |   char str_buf[STR_XL];
423  | 
424  |   GList *first_source;
425  | 
426  |   query_command->e = 0;
427  |   query_command->g = 0;
428  |   query_command->inv_attrs_bitmap = MA_new(MA_END);
429  |   query_command->recursive = 1;  /* Recursion is on by default. */
430  |   query_command->l = 0;
431  |   query_command->m = 0;
432  |   query_command->q = -1;
433  |   query_command->t = -1;
434  |   query_command->v = -1;
435  |   query_command->x = 0;
436  |   query_command->fast = 0;
437  |   query_command->filtered = 0;
438  |   query_command->L = 0;
439  |   query_command->M = 0;
440  |   query_command->R = 0;
441  |   query_command->S = 0;
442  |   query_command->object_type_bitmap = MA_new(MA_END);
443  |   /*
444  |   query_command->keytypes_bitmap = MA_new(MA_END);
445  |   */
446  |   query_command->keys = NULL;
447  | 
448  |   /* This is so Marek can't crash me :-) */
449  |   /* Side Effect - query keys are subsequently cut short to STR_S size. */
450  | 
451  |   dieif( wr_calloc((void **)&tmp_query_str, 1, STR_S+1) != UT_OK);  
452  |   strncpy(tmp_query_str, query_str, STR_S);
453  | 
454  |   /* Create the arguments. */
455  |   /* This allows only a maximum of MAX_OPT_ARG_C words in the query. */
456  |   opt_argv = g_strsplit(tmp_query_str, " ", MAX_OPT_ARG_C);
457  | 
458  |   /* Determine the number of arguments. */
459  |   for (opt_argc=0; opt_argv[opt_argc] != NULL; opt_argc++);
460  | 
461  |   while ((c = my_getopt(opt_argc, opt_argv, "aegi:klrmq:s:t:v:xFKLMRST:V:", &my_optind, &my_optarg)) != EOF) {
462  |     switch (c) {
463  |       case 'a':
464  |         /* Remove any user specified sources from the sources list. */
465  |         while ((first_source = g_list_first(qe->sources_list)) != NULL) {
466  |           qe->sources_list = g_list_remove(qe->sources_list, first_source->data);
467  |         }
468  | #if 0 
469  |         /* Add all the config sources to the sources list. */
470  |         for (i=0; CO_get_source(i) != NULL; i++) {
471  |           qe->sources_list = g_list_append(qe->sources_list, (void *)CO_get_source_database(i));
472  |         }
473  | #else
474  | 	qe->sources_list = g_list_append(qe->sources_list,  CO_get_database() );
475  | #endif
476  | 
477  |       break;
478  | 
479  |       case 'e':
480  |         query_command->e=1;
481  |       break;
482  | 
483  |       case 'g':
484  |         query_command->g=1;
485  |       break;
486  | 
487  |       case 'i':
488  |         if (my_optarg != NULL) {
489  |           inv_attrs_str = my_optarg;
490  |           /* Now a really stupid hard-coded hack to support "pn" being a synonym for "ac,tc,zc,ah" */
491  |           /* I particularly object to this because it references attributes that should only be 
492  |              defined in XML - but I don't see a simplier more robust way of doing this hack.
493  |              :-( - ottrey 8/12/99 */
494  |           if (strcmp(inv_attrs_str, "pn") == 0) {
495  | 	    dieif( wr_malloc((void **)&inv_attrs_str, 12) != UT_OK);  
496  |             strcpy(inv_attrs_str, "ac,tc,zc,ah");
497  |           }
498  |           else if (strcmp(inv_attrs_str, "ro") == 0) {
499  | 	    dieif( wr_malloc((void **)&inv_attrs_str, 12) != UT_OK); 
500  |             strcpy(inv_attrs_str, "ac,tc,zc,ah");
501  |           }
502  |           while (*inv_attrs_str) {
503  |             index = getsubopt(&inv_attrs_str, DF_get_attribute_aliases(), &value);
504  |             if (index == -1) {
505  |               attr = -1;
506  |               strcpy(str_buf, "");
507  |               sprintf(str_buf, "Unknown attribute encountered.\n"); 
508  |               SK_cd_puts(&(qe->condat), str_buf);
509  |               errflg++;
510  |             }
511  |             else {
512  |               mask_t inv_attr_mask = MA_new(INV_ATTR_MASK);
513  |               attr = DF_get_attribute_index(index);
514  |               if ( MA_isset(inv_attr_mask, attr) == 1 ) {
515  |                 /* Add the attr to the bitmap. */
516  |                 MA_set(&(query_command->inv_attrs_bitmap), attr, 1);
517  |               }
518  |               else {
519  |                 strcpy(str_buf, "");
520  |                 sprintf(str_buf, "\"%s\" does not belong to inv_attr.\n", (DF_get_attribute_aliases())[index]); 
521  |                 SK_cd_puts(&(qe->condat), str_buf);
522  |                 errflg++;
523  |               }
524  |             } 
525  |           } /* while () */
526  |         } /* if () */
527  |       break;
528  | 
529  |       case 'k':
530  |         /* This is a tricky XOR operation....  ;-)
531  |            State transition for k_flag:
532  |            0 -> 0 then k flag = 0, connected = 0
533  |            0 -> 1 then k flag = 1, connected = 1
534  |            1 -> 0 then k flag = 1, connected = 1
535  |            1 -> 1 then k flag = 0, connected = 0
536  |         */
537  |         qe->k ^= 1;
538  |       break;
539  | 
540  |       case 'r':
541  |         query_command->recursive=0;       /* Unset recursion */
542  |       break;
543  | 
544  |       case 'l':
545  |         query_command->l=1;
546  |       break;
547  | 
548  |       case 'm':
549  |         query_command->m=1;
550  |       break;
551  | 
552  |       case 'q':
553  |         if (my_optarg != NULL) {
554  |           index = getsubopt(&my_optarg, DF_get_server_queries(), &value);
555  |           if (index == -1) {
556  |             errflg++;
557  |           }
558  |           else {
559  |             query_command->q = index;
560  |           } 
561  |         } /* if () */
562  |       break;
563  | 
564  |       case 's':
565  |         if (my_optarg != NULL) {
566  |           sources_str = my_optarg;
567  |           /* Remove any sources from the sources list. */
568  |           while ((first_source = g_list_first(qe->sources_list)) != NULL) {
569  |             qe->sources_list = g_list_remove(qe->sources_list, first_source->data);
570  |           }
571  |           while (*sources_str) {
572  |             index = getsubopt(&sources_str, CO_get_sources(), &value);
573  |             if (index == -1) {
574  |               strcpy(str_buf, "");
575  |               sprintf(str_buf, "Unknown source encountered.\nNot one of: %s\n", CO_sources_to_string()); 
576  |               SK_cd_puts(&(qe->condat), str_buf);
577  | 
578  |               /* Put the default source back in. */
579  |               SK_cd_puts(&(qe->condat), "Reverting to default source - ");
580  |               SK_cd_puts(&(qe->condat), CO_get_database());
581  |               SK_cd_puts(&(qe->condat), "\n");
582  |               qe->sources_list = g_list_append(qe->sources_list, (void *)CO_get_database());
583  |               errflg++;
584  |             }
585  |             else {
586  |               qe->sources_list = g_list_append(qe->sources_list, (void *)CO_get_source_database(index));
587  |             } 
588  |           } /* while () */
589  |         } /* if () */
590  |       break;
591  | 
592  |       case 't':
593  |         if (my_optarg != NULL) {
594  |           object_types_str = my_optarg;
595  |           while (*object_types_str) {
596  |             index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
597  |             if (index == -1) {
598  |               strcpy(str_buf, "");
599  |               sprintf(str_buf, "Unknown object encountered.\n"); 
600  |               SK_cd_puts(&(qe->condat), str_buf);
601  |               errflg++;
602  |             }
603  |             else {
604  |               type = DF_get_class_index(index);
605  |               query_command->t=type;
606  |             }
607  |           }
608  |         }
609  |       break;
610  | 
611  |       case 'v':
612  |         if (my_optarg != NULL) {
613  |           object_types_str = my_optarg;
614  |           if (*object_types_str) {
615  |             index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
616  |             if (index == -1) {
617  |               strcpy(str_buf, "");
618  |               sprintf(str_buf, "Unknown object encountered.\n"); 
619  |               SK_cd_puts(&(qe->condat), str_buf);
620  |               errflg++;
621  |             }
622  |             else {
623  |               type = DF_get_class_index(index);
624  |               query_command->v=type;
625  |             }
626  |           }
627  |         }
628  |       break;
629  | 
630  |       case 'x':
631  |         query_command->x=1;
632  |       break;
633  | 
634  |       case 'F':
635  |         query_command->fast=1;
636  | 	query_command->recursive=0; /* implies no recursion */
637  |       break;
638  | 
639  |       case 'K':
640  |         query_command->filtered=1;
641  | 	query_command->recursive=0; /* implies no recursion */
642  |       break;
643  | 
644  |       case 'L':
645  |         query_command->L=1;
646  |       break;
647  | 
648  |       case 'M':
649  |         query_command->M=1;
650  |       break;
651  | 
652  |       case 'R':
653  |         query_command->R=1;
654  |       break;
655  | 
656  |       case 'S':
657  |         query_command->S=1;
658  |       break;
659  | 
660  |       case 'T':
661  |         if (my_optarg != NULL) {
662  |           object_types_str = my_optarg;
663  |           while (*object_types_str) {
664  |             index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
665  |             if (index == -1) {
666  |               strcpy(str_buf, "");
667  |               sprintf(str_buf, "Unknown class encountered.\n"); 
668  |               SK_cd_puts(&(qe->condat), str_buf);
669  |               errflg++;
670  |             }
671  |             else {
672  |               type = DF_get_class_index(index);
673  |               /* Add the type to the bitmap. */
674  |               MA_set(&(query_command->object_type_bitmap), type, 1);
675  |             }
676  |           }
677  |         }
678  |       break;
679  | 
680  |       case 'V':
681  |         if (qe->version != NULL) {
682  |           /* free up the old client info */
683  |           wr_free(qe->version);
684  |         }
685  |         
686  |         {
687  |           char *token, *cursor = my_optarg;
688  |           while( (token = strsep( &cursor, "," )) != NULL ) {
689  |             if(IP_addr_e2b( & (qe->pIP), token) 
690  |                != IP_OK ) {
691  |               /* means it was not an IP -> it was a version */
692  |               dieif( wr_malloc( (void **)&(qe->version), 
693  | 				strlen(token)+1) != UT_OK);  
694  |               strcpy(qe->version, token);
695  |             }
696  |           }
697  |         }
698  |       break;
699  | 
700  |       case '?':
701  |         errflg++;
702  |       break;
703  | 
704  |       default:
705  |         errflg++;
706  |     }
707  |   }
708  | 
709  |   /* XXX Report the error.  This could be improved. */
710  |   /*  if (opt_argv[my_optind] != NULL) { */
711  | 
712  |   /* this needed improvement, MB */
713  |   if( my_optind < opt_argc  &&  opt_argv[my_optind] != NULL) {
714  |     if ( (errflg) || (strncmp(opt_argv[my_optind], "-", 1) == 0) ) {
715  |       return -1;
716  |     }
717  |   }
718  |   else {
719  |     if (errflg) {
720  |       return -1;
721  |     }
722  |   }
723  |     
724  | 
725  |   /* Work out the length of space needed */
726  |   key_length = 0;
727  |   for (i=my_optind ; i < opt_argc; i++) {
728  |     /* length for the string + 1 for the '\0'+ 1 for the ' ' 
729  |        [MB removed: + 1 for good luck.] */
730  |     if (opt_argv[i] != NULL) {
731  |       key_length += strlen(opt_argv[i])+2;
732  |     }
733  |   }
734  | 
735  |   dieif( wr_calloc((void **)&(query_command->keys), 1, key_length+1) != UT_OK);  
736  |   strcpy(query_command->keys, "");
737  |   if (errflg == 0) {
738  |     for (i=my_optind; i < opt_argc; i++) {
739  |       strcat(query_command->keys, opt_argv[i]);
740  |       if ( (i + 1) < opt_argc) {
741  |         strcat(query_command->keys, " ");
742  |       }
743  |     }
744  |   } /* XXX - Be careful about where this brace goes. */
745  | 
746  |   /* Now convert the key to uppercase. */
747  |   for (i=0; i <= key_length; i++) {
748  |     query_command->keys[i] = toupper(query_command->keys[i]);
749  |   }
750  | 
751  |   /* Now make the keytypes_bitmap. */
752  |   query_command->keytypes_bitmap = WK_new(query_command->keys);
753  | 
754  |   if ( CO_get_comnd_logging() == 1 ) {
755  |     log_command(tmp_query_str, query_command);
756  |   }
757  | 
758  |   /* Now we don't need this anymore */
759  |   wr_free(tmp_query_str);
760  | 
761  |   return 0;
762  | 
763  | } /* QC_fill() */
764  | 
765  | /* QC_environ_new() */
766  | /*++++++++++++++++++++++++++++++++++++++
767  |   Create a new query environment.
768  | 
769  |   More:
770  |   +html+ <PRE>
771  |   Authors:
772  |         ottrey
773  |   +html+ </PRE><DL COMPACT>
774  |   +html+ <DT>Online References:
775  |   +html+ <DD><UL>
776  |   +html+ </UL></DL>
777  | 
778  |   ++++++++++++++++++++++++++++++++++++++*/
779  | Query_environ *QC_environ_new(char *ip, unsigned sock) {
780  |   Query_environ *qe;
781  | 
782  | 
783  |   dieif( wr_calloc((void **)&qe, 1, sizeof(Query_environ)+1 ) != UT_OK);  
784  |   qe->condat.ip = ip;
785  |   qe->condat.sock = sock;
786  | 
787  |   /* The source is initialized to be the one defined in the config by default. */
788  |   qe->sources_list = g_list_append(qe->sources_list, (void *)CO_get_database());
789  | 
790  |   return qe;
791  | 
792  | } /* QC_environ_new() */
793  | 
794  | Query_command *QC_create(char *input, Query_environ *qe)
795  | {
796  |   Query_command *qc;
797  | 
798  | 
799  |   dieif( wr_calloc((void **)&qc, 1, sizeof(Query_command)+1) != UT_OK);
800  |   
801  |   if ( strlen(input) == 0) {
802  |     /* An empty query (Ie return) was sent */
803  |     qc->query_type = QC_EMPTY;
804  |   } 
805  |   else {        /* else <==> input_length > 0 ) */
806  |     /* parse query */
807  |     
808  |     if( QC_fill(input, qc, qe) < 0 ) {
809  |       qc->query_type = QC_ERROR;
810  |     }
811  |     else {
812  |       /* Update the query environment */
813  |       /* qe = QC_environ_update(qc, qe); */
814  |       
815  |       /* Only do a query if there are keys. */
816  |       if (qc->keys == NULL || strlen(qc->keys) == 0 ) {
817  | 	if( strlen(qc->keys) == 0 
818  | 	    && ( qc->q != -1 || qc->t != -1 || qc->v != -1 ) ) {
819  | 	  qc->query_type = QC_TEMPLATE;
820  | 	}
821  | 	else {
822  | 	  qc->query_type = QC_NOKEY;
823  | 	}
824  |       }
825  |       else {
826  | 	if ( strcmp(qc->keys, "HELP") == 0 ) {
827  | 	  qc->query_type = QC_HELP;
828  | 	}
829  | 	/* So, a real query */
830  | 	else if( qc->filtered ) {
831  | 	  qc->query_type = QC_FILTERED;
832  | 	}
833  | 	else {
834  | 	  qc->query_type = QC_REAL;
835  | 	}
836  |       }
837  |     }
838  |   }
839  |   return qc;
840  | }
841  | 
842  | 
843  | char *QC_get_qrytype(qc_qtype_t qrytype) {
844  |   dieif(qrytype >= QC_TYPE_MAX);
845  | 
846  |   return qrytype_str[qrytype];
847  | }