1 | /***************************************
2 | $Revision: 1.36 $
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 errflg = 0;
320 | char *inv_attrs_str = NULL;
321 | char *object_types_str = NULL;
322 | char *sources_str = NULL;
323 | int opt_argc;
324 | gchar **opt_argv;
325 | char *value;
326 | char *tmp_query_str;
327 | int key_length;
328 | int i;
329 | int index;
330 | int type;
331 | int attr;
332 | char str_buf[STR_XL];
333 | getopt_state_t *gst = NULL;
334 |
335 | GList *first_source;
336 |
337 | query_command->e = 0;
338 | query_command->g = 0;
339 | query_command->inv_attrs_bitmap = MA_new(MA_END);
340 | query_command->recursive = 1; /* Recursion is on by default. */
341 | query_command->l = 0;
342 | query_command->m = 0;
343 | query_command->q = -1;
344 | query_command->t = -1;
345 | query_command->v = -1;
346 | query_command->x = 0;
347 | query_command->fast = 0;
348 | query_command->filtered = 0;
349 | query_command->L = 0;
350 | query_command->M = 0;
351 | query_command->R = 0;
352 | query_command->S = 0;
353 | query_command->object_type_bitmap = MA_new(MA_END);
354 | /*
355 | query_command->keytypes_bitmap = MA_new(MA_END);
356 | */
357 | query_command->keys = NULL;
358 |
359 | /* This is so Marek can't crash me :-) */
360 | /* Side Effect - query keys are subsequently cut short to STR_S size. */
361 |
362 | dieif( wr_calloc((void **)&tmp_query_str, 1, STR_S+1) != UT_OK);
363 | strncpy(tmp_query_str, query_str, STR_S);
364 |
365 | /* Create the arguments. */
366 | /* This allows only a maximum of MAX_OPT_ARG_C words in the query. */
367 | opt_argv = g_strsplit(tmp_query_str, " ", MAX_OPT_ARG_C);
368 |
369 | /* Determine the number of arguments. */
370 | for (opt_argc=0; opt_argv[opt_argc] != NULL; opt_argc++);
371 |
372 | dieif( (gst = mg_new(0)) == NULL );
373 |
374 | while ((c = mg_getopt(opt_argc, opt_argv, "aegi:klrmq:s:t:v:xFKLMRST:V:",
375 | gst)) != EOF) {
376 | switch (c) {
377 | case 'a':
378 | /* Remove any user specified sources from the sources list. */
379 | /* free the list only, do not touch the elements */
380 | g_list_free(qe->sources_list);
381 | qe->sources_list=NULL;
382 |
383 | /* Add all the config sources to the sources list. */
384 | {
385 | int i;
386 | ca_dbSource_t *hdl;
387 |
388 | for (i=0; (hdl = ca_get_SourceHandleByPosition(i)) != NULL; i++) {
389 | qe->sources_list = g_list_append(qe->sources_list, (void *)hdl);
390 | }
391 | }
392 |
393 |
394 | break;
395 |
396 | case 'e':
397 | query_command->e=1;
398 | break;
399 |
400 | case 'g':
401 | query_command->g=1;
402 | break;
403 |
404 | case 'i':
405 | if (gst->optarg != NULL) {
406 | char *hackstr = NULL;
407 |
408 | inv_attrs_str = gst->optarg;
409 | /* Now a really stupid hard-coded hack to support "pn" being a synonym for "ac,tc,zc,ah" */
410 | /* I particularly object to this because it references attributes that should only be
411 | defined in XML - but I don't see a simplier more robust way of doing this hack.
412 | :-( - ottrey 8/12/99
413 | ** removed a memory leak - MB, 1/08/00
414 | */
415 | if ( strcmp(inv_attrs_str, "pn") == 0
416 | || strcmp(inv_attrs_str, "ro") == 0) {
417 | wr_malloc( (void **)& hackstr, 24);
418 | strcpy(hackstr, "ac,tc,zc,ah");
419 | inv_attrs_str = hackstr;
420 | }
421 | while (*inv_attrs_str) {
422 | index = getsubopt(&inv_attrs_str, DF_get_attribute_aliases(), &value);
423 | if (index == -1) {
424 | attr = -1;
425 | strcpy(str_buf, "");
426 | sprintf(str_buf, "Unknown attribute encountered.\n");
427 | SK_cd_puts(&(qe->condat), str_buf);
428 | errflg++;
429 | }
430 | else {
431 | mask_t inv_attr_mask = MA_new(INV_ATTR_MASK);
432 | attr = DF_get_attribute_index(index);
433 | if ( MA_isset(inv_attr_mask, attr) == 1 ) {
434 | /* Add the attr to the bitmap. */
435 | MA_set(&(query_command->inv_attrs_bitmap), attr, 1);
436 | }
437 | else {
438 | strcpy(str_buf, "");
439 | sprintf(str_buf, "\"%s\" does not belong to inv_attr.\n", (DF_get_attribute_aliases())[index]);
440 | SK_cd_puts(&(qe->condat), str_buf);
441 | errflg++;
442 | }
443 | }
444 | } /* while () */
445 |
446 | if( hackstr != NULL) {
447 | wr_free(hackstr);
448 | }
449 | } /* if () */
450 | break;
451 |
452 | case 'k':
453 | /* triggering flag == a XOR operation */
454 | qe->k ^= 1;
455 | break;
456 |
457 | case 'r':
458 | query_command->recursive=0; /* Unset recursion */
459 | break;
460 |
461 | case 'l':
462 | query_command->l=1;
463 | break;
464 |
465 | case 'm':
466 | query_command->m=1;
467 | break;
468 |
469 | case 'q':
470 | if (gst->optarg != NULL) {
471 | index = getsubopt(&gst->optarg, DF_get_server_queries(), &value);
472 | if (index == -1) {
473 | errflg++;
474 | }
475 | else {
476 | query_command->q = index;
477 | }
478 | } /* if () */
479 | break;
480 |
481 | case 's':
482 | if (gst->optarg != NULL) {
483 | char *token, *cursor = gst->optarg;
484 | ca_dbSource_t *handle;
485 |
486 | /* Remove any sources from the sources list. */
487 | g_list_free(qe->sources_list);
488 | qe->sources_list=NULL;
489 |
490 | /* go through specified sources */
491 | while( (token = strsep( &cursor, "," )) != NULL ) {
492 |
493 | if( (handle = ca_get_SourceHandleByName(token)) != NULL ) {
494 | /* append */
495 | qe->sources_list
496 | = g_list_append(qe->sources_list, (void *) handle );
497 | }
498 | else {
499 | /* bail out */
500 | strcpy(str_buf, "");
501 | sprintf(str_buf, "Unknown source %s encountered.\n",token );
502 | SK_cd_puts(&(qe->condat), str_buf);
503 |
504 | /* XXX error */
505 | errflg++;
506 |
507 | } /* if handle not null */
508 | } /* while sources */
509 | } /* if argument present */
510 | break;
511 |
512 | case 't':
513 | if (gst->optarg != NULL) {
514 | object_types_str = gst->optarg;
515 | while (*object_types_str) {
516 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
517 | if (index == -1) {
518 | strcpy(str_buf, "");
519 | sprintf(str_buf, "Unknown object encountered.\n");
520 | SK_cd_puts(&(qe->condat), str_buf);
521 | errflg++;
522 | }
523 | else {
524 | type = DF_get_class_index(index);
525 | query_command->t=type;
526 | }
527 | }
528 | }
529 | break;
530 |
531 | case 'v':
532 | if (gst->optarg != NULL) {
533 | object_types_str = gst->optarg;
534 | if (*object_types_str) {
535 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
536 | if (index == -1) {
537 | strcpy(str_buf, "");
538 | sprintf(str_buf, "Unknown object encountered.\n");
539 | SK_cd_puts(&(qe->condat), str_buf);
540 | errflg++;
541 | }
542 | else {
543 | type = DF_get_class_index(index);
544 | query_command->v=type;
545 | }
546 | }
547 | }
548 | break;
549 |
550 | case 'x':
551 | query_command->x=1;
552 | break;
553 |
554 | case 'F':
555 | query_command->fast=1;
556 | query_command->recursive=0; /* implies no recursion */
557 | break;
558 |
559 | case 'K':
560 | query_command->filtered=1;
561 | query_command->recursive=0; /* implies no recursion */
562 | break;
563 |
564 | case 'L':
565 | query_command->L=1;
566 | break;
567 |
568 | case 'M':
569 | query_command->M=1;
570 | break;
571 |
572 | case 'R':
573 | query_command->R=1;
574 | break;
575 |
576 | case 'S':
577 | query_command->S=1;
578 | break;
579 |
580 | case 'T':
581 | if (gst->optarg != NULL) {
582 | object_types_str = gst->optarg;
583 | while (*object_types_str) {
584 | index = getsubopt(&object_types_str, DF_get_class_aliases(), &value);
585 | if (index == -1) {
586 | strcpy(str_buf, "");
587 | sprintf(str_buf, "Unknown class encountered.\n");
588 | SK_cd_puts(&(qe->condat), str_buf);
589 | errflg++;
590 | }
591 | else {
592 | type = DF_get_class_index(index);
593 | /* Add the type to the bitmap. */
594 | MA_set(&(query_command->object_type_bitmap), type, 1);
595 | }
596 | }
597 | }
598 | break;
599 |
600 | case 'V':
601 | if (qe->version != NULL) {
602 | /* free up the old client info */
603 | wr_free(qe->version);
604 | }
605 |
606 | {
607 | char *token, *cursor = gst->optarg;
608 | while( (token = strsep( &cursor, "," )) != NULL ) {
609 | if(IP_addr_e2b( & (qe->pIP), token)
610 | != IP_OK ) {
611 | /* means it was not an IP -> it was a version */
612 | dieif( wr_malloc( (void **)&(qe->version),
613 | strlen(token)+1) != UT_OK);
614 | strcpy(qe->version, token);
615 | }
616 | }
617 | }
618 | break;
619 |
620 | /* any other flag, including '?' and ':' errors */
621 | default:
622 | errflg++;
623 | }
624 | }
625 |
626 | /* copy the key */
627 |
628 | /* Work out the length of space needed */
629 | key_length = 1; /* for terminal '\0' */
630 | for (i=gst->optind ; i < opt_argc; i++) {
631 | /* length for the string + 1 for the '\0'+ 1 for the ' ' */
632 | if (opt_argv[i] != NULL) {
633 | key_length += strlen(opt_argv[i])+1;
634 | }
635 | }
636 | /* allocate */
637 | dieif( wr_calloc((void **)&(query_command->keys), 1, key_length+1) != UT_OK);
638 | /* copy */
639 | for (i=gst->optind; i < opt_argc; i++) {
640 | strcat(query_command->keys, opt_argv[i]);
641 | if ( (i + 1) < opt_argc) {
642 | strcat(query_command->keys, " ");
643 | }
644 | }
645 |
646 | /* if no error, process the key, otherwise don't bother */
647 | if ( ! errflg ) {
648 | /* convert the key to uppercase. */
649 | for (i=0; i <= key_length; i++) {
650 | query_command->keys[i] = toupper(query_command->keys[i]);
651 | }
652 |
653 | /* make the keytypes_bitmap. */
654 | query_command->keytypes_bitmap = WK_new(query_command->keys);
655 |
656 | /* tracing */
657 | if ( CO_get_comnd_logging() == 1 ) {
658 | log_command(tmp_query_str, query_command);
659 | }
660 | } /* if no error */
661 |
662 | /* we don't need this anymore */
663 | wr_free(tmp_query_str);
664 | wr_free(gst);
665 |
666 | return (errflg) ? -1 : 0; /* return -1 on error */
667 |
668 | } /* QC_fill() */
669 |
670 | /* QC_environ_new() */
671 | /*++++++++++++++++++++++++++++++++++++++
672 | Create a new query environment.
673 |
674 | More:
675 | +html+ <PRE>
676 | Authors:
677 | ottrey
678 | +html+ </PRE><DL COMPACT>
679 | +html+ <DT>Online References:
680 | +html+ <DD><UL>
681 | +html+ </UL></DL>
682 |
683 | ++++++++++++++++++++++++++++++++++++++*/
684 | Query_environ *QC_environ_new(char *ip, unsigned sock) {
685 | Query_environ *qe;
686 |
687 |
688 | dieif( wr_calloc((void **)&qe, 1, sizeof(Query_environ)+1 ) != UT_OK);
689 | qe->condat.ip = ip;
690 | qe->condat.sock = sock;
691 |
692 | /* The source is initialized to include only the deflook sources */
693 | {
694 | int i;
695 | ca_dbSource_t *hdl;
696 |
697 | for (i=0; (hdl = ca_get_SourceHandleByPosition(i)) != NULL; i++) {
698 | if( ca_get_srcdeflook(hdl) ) {
699 | qe->sources_list = g_list_append(qe->sources_list, (void *)hdl);
700 | }
701 | }
702 | }
703 |
704 | return qe;
705 |
706 | } /* QC_environ_new() */
707 |
708 |
709 |
710 | /*++ QC_create()
711 |
712 | try to parse the query and fill in the QC struct, setting
713 | qc->query_type accordingly.
714 |
715 | by marek.
716 | ++++++++++++++++++++++++++++++++++++++*/
717 | Query_command *QC_create(char *input, Query_environ *qe)
718 | {
719 | Query_command *qc;
720 | /* allocate place for a copy of the input */
721 | char *copy = calloc(1,strlen(input)+1);
722 | char *ci, *co;
723 | /* clean the string from junk - allow only known chars, something like
724 | tr/A-Za-z0-9\-\_\:\+\=\.\,\@\/ \n//cd;
725 | */
726 |
727 | dieif(copy == NULL);
728 |
729 | for(ci = input, co = copy; *ci != 0; ci++) {
730 | if( strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* only those are allowed */
731 | "abcdefghijklmnopqrstuvwxyz"
732 | "0123456789-_:+=.,@/' \n", *ci) != NULL) {
733 | *(co++) = *ci;
734 | }
735 | }
736 |
737 | /* now delete whitespace chars at the end */
738 | co--;
739 | while( isspace(*co) ) {
740 | *co = '\0';
741 | co--;
742 | }
743 |
744 |
745 | dieif( wr_calloc((void **)&qc, 1, sizeof(Query_command)+1) != UT_OK);
746 |
747 | if ( strlen(copy) == 0) {
748 | /* An empty query (Ie return) was sent */
749 | qc->query_type = QC_EMPTY;
750 | }
751 | else { /* else <==> input_length > 0 ) */
752 | /* parse query */
753 |
754 | if( QC_fill(copy, qc, qe) < 0 ) {
755 | qc->query_type = QC_ERROR;
756 | }
757 | else {
758 | /* Update the query environment */
759 | /* qe = QC_environ_update(qc, qe); */
760 |
761 | /* Only do a query if there are keys. */
762 | if (qc->keys == NULL || strlen(qc->keys) == 0 ) {
763 | if( strlen(qc->keys) == 0
764 | && ( qc->q != -1 || qc->t != -1 || qc->v != -1 ) ) {
765 | qc->query_type = QC_TEMPLATE;
766 | }
767 | else {
768 | qc->query_type = QC_NOKEY;
769 | }
770 | }
771 | else {
772 | if ( strcmp(qc->keys, "HELP") == 0 ) {
773 | qc->query_type = QC_HELP;
774 | }
775 | /* So, a real query */
776 | else if( qc->filtered ) {
777 | qc->query_type = QC_FILTERED;
778 | }
779 | else {
780 | qc->query_type = QC_REAL;
781 | }
782 | }
783 | }
784 | }
785 |
786 | free(copy);
787 |
788 | return qc;
789 | }
790 |
791 |
792 | char *QC_get_qrytype(qc_qtype_t qrytype) {
793 | dieif(qrytype >= QC_TYPE_MAX);
794 |
795 | return qrytype_str[qrytype];
796 | }