1 | /***************************************
2 | $Revision: 1.41 $
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 | Author : ottrey@ripe.net
12 | Modifications by : 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 | #include "ca_configFns.h"
47 | #include "ca_dictSyms.h"
48 | #include "ca_macros.h"
49 | #include "ca_srcAttribs.h"
50 |
51 | #include "getopt.h"
52 |
53 | #define MAX_OPT_ARG_C 20
54 |
55 | /*+ String sizes +*/
56 | #define STR_S 63
57 | #define STR_M 255
58 | #define STR_L 1023
59 | #define STR_XL 4095
60 | #define STR_XXL 16383
61 |
62 | /*
63 | make sources list (allocated string).
64 | expects list to hold source handles
65 | */
66 | char *
67 | qc_sources_list_to_string(GList *list)
68 | {
69 | char *result = NULL;
70 | int oldlen = 0;
71 | GList *qitem;
72 |
73 | for( qitem = g_list_first(list);
74 | qitem != NULL;
75 | qitem = g_list_next(qitem)) {
76 | ca_dbSource_t *source_hdl = (ca_dbSource_t *) ( qitem->data );
77 | char *srcname = ca_get_srcname( source_hdl );
78 |
79 | dieif( wr_realloc( (void **)& result, oldlen + strlen(srcname) + 2)
80 | != UT_OK);
81 | if(oldlen > 0) {
82 | strcat(result, ",");
83 | }
84 | strcat(result, srcname);
85 | }
86 |
87 | return result;
88 | }
89 |
90 | /* QC_environ_to_string() */
91 | /*++++++++++++++++++++++++++++++++++++++
92 | Convert the query_environ to a string.
93 |
94 | Query_environ *query_environ The query_environ to be converted.
95 |
96 | More:
97 | +html+ <PRE>
98 | Authors:
99 | ottrey
100 | +html+ </PRE><DL COMPACT>
101 | +html+ <DT>Online References:
102 | +html+ <DD><UL>
103 | +html+ </UL></DL>
104 |
105 | ++++++++++++++++++++++++++++++++++++++*/
106 | char *QC_environ_to_string(Query_environ qe) {
107 | char *result;
108 | char *str1;
109 | char str2[IP_ADDRSTR_MAX];
110 | char result_buf[STR_XL];
111 |
112 | str1 = qc_sources_list_to_string(qe.sources_list);
113 |
114 | if( IP_addr_b2a( &(qe.pIP), str2, IP_ADDRSTR_MAX) != IP_OK ) {
115 | *str2 = '\0';
116 | }
117 |
118 | sprintf(result_buf, "host=%s, keep_connection=%s, sources=%s, version=%s%s%s", qe.condat.ip,
119 | qe.k?"on":"off",
120 | str1,
121 | (qe.version == NULL) ? "?" : qe.version,
122 | *str2 == '\0' ? "" : ", passedIP=",
123 | *str2 == '\0' ? "" : str2
124 | );
125 |
126 | wr_free(str1);
127 |
128 | dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);
129 |
130 | strcpy(result, result_buf);
131 |
132 | return result;
133 |
134 | } /* QC_environ_to_string() */
135 |
136 | /* QC_query_command_to_string() */
137 | /*++++++++++++++++++++++++++++++++++++++
138 | Convert the query_command to a string.
139 |
140 | Query_command *query_command The query_command to be converted.
141 |
142 | More:
143 | +html+ <PRE>
144 | Authors:
145 | ottrey
146 | +html+ </PRE><DL COMPACT>
147 | +html+ <DT>Online References:
148 | +html+ <DD><UL>
149 | +html+ </UL></DL>
150 |
151 | ++++++++++++++++++++++++++++++++++++++*/
152 | char *QC_query_command_to_string(Query_command *query_command) {
153 | char *result;
154 | char result_buf[STR_XL];
155 | char *str1;
156 | char *str2;
157 | char *str3;
158 |
159 | str1 = MA_to_string(query_command->inv_attrs_bitmap, DF_get_attribute_names());
160 | str2 = MA_to_string(query_command->object_type_bitmap, DF_get_class_names());
161 | str3 = WK_to_string(query_command->keytypes_bitmap);
162 |
163 | 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]",
164 | str1,
165 | query_command->recursive?"y":"n",
166 | str2,
167 | query_command->e,
168 | query_command->g,
169 | query_command->l,
170 | query_command->m,
171 | query_command->q,
172 | query_command->t,
173 | query_command->v,
174 | query_command->x,
175 | query_command->fast,
176 | query_command->filtered,
177 | query_command->L,
178 | query_command->M,
179 | query_command->R,
180 | query_command->S,
181 | str3,
182 | query_command->keys);
183 | wr_free(str1);
184 | wr_free(str2);
185 | wr_free(str3);
186 |
187 | dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);
188 | strcpy(result, result_buf);
189 |
190 | return result;
191 |
192 | } /* QC_query_command_to_string() */
193 |
194 | /* log_command() */
195 | /*++++++++++++++++++++++++++++++++++++++
196 | Log the command.
197 | This is more to do with Tracing. And should/will get merged with a tracing
198 | module (when it is finalized.)
199 |
200 | char *query_str
201 |
202 | Query_command *query_command
203 |
204 | More:
205 | +html+ <PRE>
206 | Authors:
207 | ottrey
208 | +html+ </PRE><DL COMPACT>
209 | +html+ <DT>Online References:
210 | +html+ <DD><UL>
211 | +html+ </UL></DL>
212 |
213 | ++++++++++++++++++++++++++++++++++++++*/
214 | static void log_command(char *query_str, Query_command *query_command) {
215 | char *str;
216 |
217 | if( ER_is_traced(FAC_QC, ASP_QC_BUILD) ) {
218 | str = QC_query_command_to_string(query_command);
219 | ER_dbg_va(FAC_QC, ASP_QC_BUILD,
220 | "query=[%s] %s", query_str, str);
221 | wr_free(str);
222 | }
223 | } /* log_command() */
224 |
225 | /* QC_environ_free() */
226 | /*++++++++++++++++++++++++++++++++++++++
227 | Free the query_environ.
228 |
229 | Query_command *qc query_environ to be freed.
230 |
231 | More:
232 | +html+ <PRE>
233 | Authors:
234 | ottrey
235 | +html+ </PRE><DL COMPACT>
236 | +html+ <DT>Online References:
237 | +html+ <DD><UL>
238 | +html+ </UL></DL>
239 |
240 | ++++++++++++++++++++++++++++++++++++++*/
241 | void QC_environ_free(Query_environ *qe) {
242 | if (qe != NULL) {
243 | if (qe->version != NULL) {
244 | wr_free(qe->version);
245 | }
246 |
247 | if (qe->sources_list != NULL) {
248 | g_list_free(qe->sources_list);
249 | qe->sources_list=NULL;
250 | }
251 | wr_free(qe);
252 | }
253 | } /* QC_environ_free() */
254 |
255 | /* QC_free() */
256 | /*++++++++++++++++++++++++++++++++++++++
257 | Free the query_command.
258 |
259 | Query_command *qc query_command to be freed.
260 |
261 | XXX I'm not sure the bitmaps will get freed.
262 | qc->inv_attrs_bitmap
263 | qc->object_type_bitmap
264 | qc->keytypes_bitmap
265 |
266 | More:
267 | +html+ <PRE>
268 | Authors:
269 | ottrey
270 | +html+ </PRE><DL COMPACT>
271 | +html+ <DT>Online References:
272 | +html+ <DD><UL>
273 | +html+ </UL></DL>
274 |
275 | ++++++++++++++++++++++++++++++++++++++*/
276 | void QC_free(Query_command *qc) {
277 | if (qc != NULL) {
278 | if (qc->keys != NULL) {
279 | wr_free(qc->keys);
280 | }
281 | wr_free(qc);
282 | }
283 | } /* QC_free() */
284 |
285 |
286 |
287 | /* QC_fill() */
288 | /*++++++++++++++++++++++++++++++++++++++
289 | Create a new query_command.
290 |
291 |
292 |
293 | char *query_str The garden variety whois query string.
294 |
295 | Query_environ *qe the environment
296 |
297 | Pre-condition:
298 |
299 | Returns -1 when query incorrect, 0 otherwise
300 |
301 | More:
302 | +html+ <PRE>
303 | Authors:
304 | ottrey - original code
305 | marek - modified for my getopts, multiple sources;
306 | and generally cleaned.
307 | +html+ </PRE><DL COMPACT>
308 | +html+ <DT>Online References:
309 | +html+ <DD><UL>
310 | +html+ </UL></DL>
311 |
312 | ++++++++++++++++++++++++++++++++++++++*/
313 | static
314 | int QC_fill(char *query_str,
315 | Query_command *query_command,
316 | Query_environ *qe) {
317 |
318 | int c;
319 | int synerrflg = 0;
320 | int badparerr = 0;
321 | int minusk = 0;
322 | char *inv_attrs_str = NULL;
323 | char *object_types_str = NULL;
324 | int opt_argc;
325 | gchar **opt_argv;
326 | char *value;
327 | char *tmp_query_str;
328 | int key_length;
329 | int i;
330 | int index;
331 | int type;
332 | int attr;
333 | char str_buf[STR_XL];
334 | getopt_state_t *gst = NULL;
335 |
336 | query_command->e = 0;
337 | query_command->g = 0;
338 | query_command->inv_attrs_bitmap = MA_new(MA_END);
339 | query_command->recursive = 1; /* Recursion is on by default. */
340 | query_command->l = 0;
341 | query_command->m = 0;
342 | query_command->q = -1;
343 | query_command->t = -1;
344 | query_command->v = -1;
345 | query_command->x = 0;
346 | query_command->fast = 0;
347 | query_command->filtered = 0;
348 | query_command->L = 0;
349 | query_command->M = 0;
350 | query_command->R = 0;
351 | query_command->S = 0;
352 | query_command->object_type_bitmap = MA_new(MA_END);
353 | /*
354 | query_command->keytypes_bitmap = MA_new(MA_END);
355 | */
356 | query_command->keys = NULL;
357 |
358 | /* This is so Marek can't crash me :-) */
359 | /* Side Effect - query keys are subsequently cut short to STR_S size. */
360 |
361 | dieif( wr_calloc((void **)&tmp_query_str, 1, STR_S+1) != UT_OK);
362 | strncpy(tmp_query_str, query_str, STR_S);
363 |
364 | /* Create the arguments. */
365 | /* This allows only a maximum of MAX_OPT_ARG_C words in the query. */
366 | opt_argv = g_strsplit(tmp_query_str, " ", MAX_OPT_ARG_C);
367 |
368 | /* Determine the number of arguments. */
369 | for (opt_argc=0; opt_argv[opt_argc] != NULL; opt_argc++);
370 |
371 | dieif( (gst = mg_new(0)) == NULL );
372 |
373 | while ((c = mg_getopt(opt_argc, opt_argv, "aegi:klrmq:s:t:v:xFKLMRST:V:",
374 | gst)) != EOF) {
375 | switch (c) {
376 | case 'a':
377 | /* Remove any user specified sources from the sources list. */
378 | /* free the list only, do not touch the elements */
379 | g_list_free(qe->sources_list);
380 | qe->sources_list=NULL;
381 |
382 | /* Add all the config sources to the sources list. */
383 | {
384 | int i;
385 | ca_dbSource_t *hdl;
386 |
387 | for (i=0; (hdl = ca_get_SourceHandleByPosition(i)) != NULL; i++) {
388 | qe->sources_list = g_list_append(qe->sources_list, (void *)hdl);
389 | }
390 | }
391 |
392 |
393 | break;
394 |
395 | case 'e':
396 | query_command->e=1;
397 | break;
398 |
399 | case 'g':
400 | query_command->g=1;
401 | break;
402 |
403 | case 'i':
404 | if (gst->optarg != NULL) {
405 | char *hackstr = NULL;
406 |
407 | inv_attrs_str = gst->optarg;
408 | /* Now a really stupid hard-coded hack to support "pn" being a synonym for "ac,tc,zc,ah" */
409 | /* I particularly object to this because it references attributes that should only be
410 | defined in XML - but I don't see a simplier more robust way of doing this hack.
411 | :-( - ottrey 8/12/99
412 | ** removed a memory leak - MB, 1/08/00
413 | */
414 | if ( strcmp(inv_attrs_str, "pn") == 0
415 | || strcmp(inv_attrs_str, "ro") == 0) {
416 | wr_malloc( (void **)& hackstr, 24); /* make a copy */
417 | strcpy(hackstr, "ac,tc,zc,ah");
418 | inv_attrs_str = hackstr;
419 | }
420 | while (*inv_attrs_str) {
421 | index = getsubopt(&inv_attrs_str, DF_get_attribute_aliases(), &value);
422 | if (index == -1) {
423 | attr = -1;
424 | strcpy(str_buf, "");
425 | sprintf(str_buf, "Unknown attribute encountered.\n");
426 | SK_cd_puts(&(qe->condat), str_buf);
427 | badparerr++;
428 | }
429 | else {
430 | mask_t inv_attr_mask = MA_new(INV_ATTR_MASK);
431 | attr = DF_get_attribute_index(index);
432 | if ( MA_isset(inv_attr_mask, attr) == 1 ) {
433 | /* Add the attr to the bitmap. */
434 | MA_set(&(query_command->inv_attrs_bitmap), attr, 1);
435 | }
436 | else {
437 | strcpy(str_buf, "");
438 | sprintf(str_buf, "\"%s\" is not an inverse searchable attribute.\n", (DF_get_attribute_aliases())[index]);
439 | SK_cd_puts(&(qe->condat), str_buf);
440 | badparerr++;
441 | }
442 | }
443 | } /* while () */
444 |
445 | if( hackstr != NULL) {
446 | wr_free(hackstr);
447 | }
448 | } /* if () */
449 | break;
450 |
451 | case 'k':
452 | minusk = 1;
453 | break;
454 |
455 | case 'r':
456 | query_command->recursive=0; /* Unset recursion */
457 | break;
458 |
459 | case 'l':
460 | query_command->l=1;
461 | break;
462 |
463 | case 'm':
464 | query_command->m=1;
465 | break;
466 |
467 | case 'q':
468 | if (gst->optarg != NULL) {
469 | index = getsubopt(&gst->optarg, DF_get_server_queries(), &value);
470 | if (index == -1) {
471 | synerrflg++;
472 | }
473 | else {
474 | query_command->q = index;
475 | }
476 | } /* if () */
477 | break;
478 |
479 | case 's':
480 | if (gst->optarg != NULL) {
481 | char *token, *cursor = gst->optarg;
482 | ca_dbSource_t *handle;
483 |
484 | /* Remove any sources from the sources list. */
485 | g_list_free(qe->sources_list);
486 | qe->sources_list=NULL;
487 |
488 | /* go through specified sources */
489 | while( (token = strsep( &cursor, "," )) != NULL ) {
490 |
491 | if( (handle = ca_get_SourceHandleByName(token)) != NULL ) {
492 | /* append */
493 | qe->sources_list
494 | = g_list_append(qe->sources_list, (void *) handle );
495 | }
496 | else {
497 | /* bail out */
498 |
499 | SK_cd_printf(&(qe->condat),
500 | "%% Unknown source %s requested.\n",token );
501 |
502 | /* XXX error */
503 | badparerr++;
504 |
505 | } /* if handle not null */
506 | } /* while sources */
507 | } /* if argument present */
508 | break;
509 |
510 | case 't':
511 | if (gst->optarg != NULL) {
512 | object_types_str = gst->optarg;
513 | while (*object_types_str) {
514 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
515 | if (index == -1) {
516 | strcpy(str_buf, "");
517 | sprintf(str_buf, "Unknown object encountered.\n");
518 | SK_cd_puts(&(qe->condat), str_buf);
519 | badparerr++;
520 | }
521 | else {
522 | type = DF_get_class_index(index);
523 | query_command->t=type;
524 | }
525 | }
526 | }
527 | break;
528 |
529 | case 'v':
530 | if (gst->optarg != NULL) {
531 | object_types_str = gst->optarg;
532 | if (*object_types_str) {
533 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
534 | if (index == -1) {
535 | strcpy(str_buf, "");
536 | sprintf(str_buf, "Unknown object encountered.\n");
537 | SK_cd_puts(&(qe->condat), str_buf);
538 | badparerr++;
539 | }
540 | else {
541 | type = DF_get_class_index(index);
542 | query_command->v=type;
543 | }
544 | }
545 | }
546 | break;
547 |
548 | case 'x':
549 | query_command->x=1;
550 | break;
551 |
552 | case 'F':
553 | query_command->fast=1;
554 | query_command->recursive=0; /* implies no recursion */
555 | break;
556 |
557 | case 'K':
558 | query_command->filtered=1;
559 | query_command->recursive=0; /* implies no recursion */
560 | break;
561 |
562 | case 'L':
563 | query_command->L=1;
564 | break;
565 |
566 | case 'M':
567 | query_command->M=1;
568 | break;
569 |
570 | case 'R':
571 | query_command->R=1;
572 | break;
573 |
574 | case 'S':
575 | query_command->S=1;
576 | break;
577 |
578 | case 'T':
579 | if (gst->optarg != NULL) {
580 | object_types_str = gst->optarg;
581 | while (*object_types_str) {
582 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
583 | if (index == -1) {
584 | strcpy(str_buf, "");
585 | sprintf(str_buf, "Unknown object type encountered.\n");
586 | SK_cd_puts(&(qe->condat), str_buf);
587 | badparerr++;
588 | }
589 | else {
590 | type = DF_get_class_index(index);
591 | /* Add the type to the bitmap. */
592 | MA_set(&(query_command->object_type_bitmap), type, 1);
593 | }
594 | }
595 | }
596 | break;
597 |
598 | case 'V':
599 | if (qe->version != NULL) {
600 | /* free up the old client info */
601 | wr_free(qe->version);
602 | }
603 |
604 | {
605 | char *token, *cursor = gst->optarg;
606 | while( (token = strsep( &cursor, "," )) != NULL ) {
607 | if(IP_addr_e2b( & (qe->pIP), token)
608 | != IP_OK ) {
609 | /* means it was not an IP -> it was a version */
610 | dieif( wr_malloc( (void **)&(qe->version),
611 | strlen(token)+1) != UT_OK);
612 | strcpy(qe->version, token);
613 | }
614 | }
615 | }
616 | break;
617 |
618 | /* any other flag, including '?' and ':' errors */
619 | default:
620 | synerrflg++;
621 | }
622 | }
623 |
624 | /* copy the key */
625 |
626 | /* Work out the length of space needed */
627 | key_length = 1; /* for terminal '\0' */
628 | for (i=gst->optind ; i < opt_argc; i++) {
629 | /* length for the string + 1 for the '\0'+ 1 for the ' ' */
630 | if (opt_argv[i] != NULL) {
631 | key_length += strlen(opt_argv[i])+1;
632 | }
633 | }
634 | /* allocate */
635 | dieif( wr_calloc((void **)&(query_command->keys), 1, key_length+1) != UT_OK);
636 | /* copy */
637 | for (i=gst->optind; i < opt_argc; i++) {
638 | strcat(query_command->keys, opt_argv[i]);
639 | if ( (i + 1) < opt_argc) {
640 | strcat(query_command->keys, " ");
641 | }
642 | }
643 |
644 | /* if no error, process the key, otherwise don't bother */
645 | if ( ! synerrflg && ! badparerr ) {
646 | /* convert the key to uppercase. */
647 | for (i=0; i <= key_length; i++) {
648 | query_command->keys[i] = toupper(query_command->keys[i]);
649 | }
650 |
651 | /* make the keytypes_bitmap. */
652 | query_command->keytypes_bitmap = WK_new(query_command->keys);
653 |
654 | /* tracing */
655 | log_command(tmp_query_str, query_command);
656 |
657 |
658 | /* "keep connection" processing:
659 | when opening connection, -k may be alone or with a query
660 | later -k must appear alone (or there must be an empty line,
661 | or an error) for the connection to close.
662 | */
663 | if( minusk ) {
664 | if( qe->k == 0 ) { /* opening */
665 | qe->k = 1;
666 | }
667 | else { /* closing, if no key; otherwise keep open */
668 | if( key_length <= 1 ) {
669 | qe->k = 0;
670 | }
671 | }
672 | }
673 |
674 | } /* if no error */
675 |
676 | /* we don't need this anymore */
677 | wr_free(tmp_query_str);
678 | wr_free(gst);
679 |
680 | if(synerrflg > 0) { /* severe syntax error. Usage must be printed */
681 | return QC_SYNERR;
682 | }
683 | else if(badparerr > 0) { /* the requester has a clue. No Usage info */
684 | return QC_PARERR;
685 | }
686 | else {
687 | return 0;
688 | }
689 | } /* QC_fill() */
690 |
691 | /* QC_environ_new() */
692 | /*++++++++++++++++++++++++++++++++++++++
693 | Create a new query environment.
694 |
695 | More:
696 | +html+ <PRE>
697 | Authors:
698 | ottrey
699 | +html+ </PRE><DL COMPACT>
700 | +html+ <DT>Online References:
701 | +html+ <DD><UL>
702 | +html+ </UL></DL>
703 |
704 | ++++++++++++++++++++++++++++++++++++++*/
705 | Query_environ *QC_environ_new(char *ip, unsigned sock) {
706 | Query_environ *qe;
707 |
708 |
709 | dieif( wr_calloc((void **)&qe, 1, sizeof(Query_environ)+1 ) != UT_OK);
710 | qe->condat.ip = ip;
711 | qe->condat.sock = sock;
712 |
713 | /* The source is initialized to include only the deflook sources */
714 | {
715 | int i;
716 | ca_dbSource_t *hdl;
717 |
718 | for (i=0; (hdl = ca_get_SourceHandleByPosition(i)) != NULL; i++) {
719 | if( ca_get_srcdeflook(hdl) ) {
720 | qe->sources_list = g_list_append(qe->sources_list, (void *)hdl);
721 | }
722 | }
723 | }
724 |
725 | return qe;
726 |
727 | } /* QC_environ_new() */
728 |
729 |
730 |
731 | /*++ QC_create()
732 |
733 | try to parse the query and fill in the QC struct, setting
734 | qc->query_type accordingly.
735 |
736 | by marek.
737 | ++++++++++++++++++++++++++++++++++++++*/
738 | Query_command *QC_create(char *input, Query_environ *qe)
739 | {
740 | Query_command *qc;
741 | /* allocate place for a copy of the input */
742 | char *copy = calloc(1,strlen(input)+1);
743 | char *ci, *co;
744 | int qt;
745 | /* clean the string from junk - allow only known chars, something like
746 | tr/A-Za-z0-9\-\_\:\+\=\.\,\@\/ \n//cd;
747 |
748 | strip leading spaces too
749 | */
750 |
751 | dieif(copy == NULL);
752 |
753 | for(ci = input; *ci != 0 && isspace(*ci); ci++) {
754 | /* EMPTY */
755 | }
756 |
757 | for(co = copy; *ci != 0; ci++) {
758 | if( strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* only those are allowed */
759 | "abcdefghijklmnopqrstuvwxyz"
760 | "0123456789-_:+=.,@/' \n", *ci) != NULL) {
761 | *(co++) = *ci;
762 | }
763 | }
764 |
765 | /* now delete whitespace chars at the end */
766 | co--;
767 | while( isspace(*co) ) {
768 | *co = '\0';
769 | co--;
770 | }
771 |
772 |
773 | dieif( wr_calloc((void **)&qc, 1, sizeof(Query_command)+1) != UT_OK);
774 |
775 | if ( strlen(copy) == 0) {
776 | /* An empty query (Ie return) was sent */
777 | qc->query_type = QC_EMPTY;
778 | }
779 | else { /* else <==> input_length > 0 ) */
780 | /* parse query */
781 | qt = QC_fill(copy, qc, qe);
782 |
783 | if( qt == QC_SYNERR || qt == QC_PARERR ) {
784 | qc->query_type = qt;
785 | }
786 | else {
787 | /* Update the query environment */
788 | /* qe = QC_environ_update(qc, qe); */
789 |
790 | /* Only do a query if there are keys. */
791 | if (qc->keys == NULL || strlen(qc->keys) == 0 ) {
792 | if( strlen(qc->keys) == 0
793 | && ( qc->q != -1 || qc->t != -1 || qc->v != -1 ) ) {
794 | qc->query_type = QC_TEMPLATE;
795 | }
796 | else {
797 | qc->query_type = QC_NOKEY;
798 | }
799 | }
800 | else {
801 | if ( strcmp(qc->keys, "HELP") == 0 ) {
802 | qc->query_type = QC_HELP;
803 | }
804 | /* So, a real query */
805 | else if( qc->filtered ) {
806 | qc->query_type = QC_FILTERED;
807 | }
808 | else {
809 | qc->query_type = QC_REAL;
810 | }
811 | }
812 | }
813 | }
814 |
815 | free(copy);
816 |
817 | return qc;
818 | }
819 |
820 |
821 | char *QC_get_qrytype(qc_qtype_t qrytype) {
822 | dieif(qrytype >= QC_TYPE_MAX);
823 |
824 | return qrytype_str[qrytype];
825 | }