## modules/qc/query_command.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. qc_sources_list_to_string
2. QC_environ_to_string
3. QC_query_command_to_string
4. log_command
5. QC_environ_free
6. QC_free
7. QC_fill
8. QC_environ_new
9. QC_create
10. 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 }

/* [<][>][^][v][top][bottom][index][help] */