modules/qc/query_command.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- qc_sources_list_to_string
- QC_environ_to_string
- QC_query_command_to_string
- log_command
- QC_environ_free
- QC_free
- QC_fill
- QC_environ_new
- QC_create
- QC_get_qrytype
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
793 dieif(qrytype >= QC_TYPE_MAX);
794
795 return qrytype_str[qrytype];
796 }