modules/qc/query_command.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- QC_bitmap_to_string
- my_getopt
- QC_query_command_to_string
- log_command
- QC_free
- QC_new
- QC_environ_update
/***************************************
$Revision: 1.10 $
Query command module (qc). This is what the whois query gets stored as in
memory.
Status: NOT REVUED, NOT TESTED
******************/ /******************
Filename : query_command.c
Author : ottrey@ripe.net
OSs Tested : Solaris
To Do : Write some kind of options parser (to check for valid
combinations of options.)
Comments :
******************/ /******************
Copyright (c) 1999 RIPE NCC
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
***************************************/
#include <stdlib.h>
#include <stdio.h>
#include "query_command.h"
#include "objects.h"
#include "constants.h"
#include "which_keytypes.h"
#define MAX_OPT_ARG_C 20
/*+ String sizes +*/
#define STR_S 63
#define STR_M 255
#define STR_L 1023
#define STR_XL 4095
#define STR_XXL 16383
/* XXX These probably wont get used. I'm using a switch statement instead. -ottrey 5/7/99 */
/*
mask_t Inv_attr_mask;
mask_t Object_mask;
*/
/* QC_bitmap_to_string() */
/*++++++++++++++++++++++++++++++++++++++
Convert the bitmap of attributes used in this query_command to a string.
mask_t bitmap The bitmap of attribute to be converted.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
char *QC_bitmap_to_string(mask_t bitmap) {
/* [<][>][^][v][top][bottom][index][help] */
return MA_to_string(bitmap, AT_get_attributes(), DUP_TOKENS, 0);
} /* QC_bitmap_to_string() */
/* my_getopt() */
/*++++++++++++++++++++++++++++++++++++++
A thread safe version of getopt, used to get the options from the whois
query.
int opt_argc The number of query arguments.
char **opt_argv The query arguments.
char *optstring The string containing valid options.
int *my_optind_ptr A pointer to the index into the options of the option
returned.
char **my_optarg_ptr A pointer to the arguments to be returned.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ <LI>man getopt
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
static int my_getopt(int opt_argc, char **opt_argv, char *optstring, int *my_optind_ptr, char **my_optarg_ptr) {
/* [<][>][^][v][top][bottom][index][help] */
int c='?';
int i, j;
int no_options;
int optind = *my_optind_ptr;
char option[3];
int option_matched=0;
/* Get the number of options in the option string */
for(i=0, no_options=0; i < strlen(optstring) ; i++) {
if (optstring[i] != ':') {
no_options++;
}
}
/* Iterate through all the option until it matches the current opt_argv */
/* Ie. opt_argv[optind] */
for (i=0, j=0; i <= no_options; i++, j++) {
/* Construct one option from the optstring */
option[0] = '-';
if (optstring[j] == ':') {
j++;
}
option[1] = optstring[j];
if ( optstring[j+1] == ':' ) {
option[2] = ':';
}
else {
option[2] = '\0';
}
option[3] = '\0';
if (optind < opt_argc) {
if (strlen(opt_argv[optind]) > 0) {
/*
printf("opt_argv[%d] == option <==> %s == %s\n", optind, opt_argv[optind], option);
*/
if (strncmp(opt_argv[optind], option, 2) == 0) {
/* Does the option have arguments. */
if (option[2] == ':') {
/* If the option has arguments */
if (strlen(opt_argv[optind]) > 2) {
/* If the arguments are in this token */
*my_optarg_ptr = (opt_argv[optind])+2;
}
else {
/* If the arguments are in the next token */
*my_optarg_ptr = opt_argv[optind+1];
optind++;
}
}
else {
/* There are no arguments to this token */
*my_optarg_ptr = NULL;
}
/* Option matched - break out of the search */
option_matched = 1;
break;
}
}
}
} /* for() */
if ( option_matched == 1 ) {
/* This option was matched, return it. */
c = option[1];
/* Move to the next opt_argv */
optind++;
*my_optind_ptr = optind;
}
else {
/* Discontinue search */
c = EOF;
}
return c;
} /* my_getopt() */
/* QC_query_command_to_string() */
/*++++++++++++++++++++++++++++++++++++++
Convert the query_command to a string.
Query_command *query_command The query_command to be converted.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
char *QC_query_command_to_string(Query_command *query_command) {
/* [<][>][^][v][top][bottom][index][help] */
char *result;
char result_buf[STR_XL];
char *str1;
char *str2;
char *str3;
char *str4;
str1 = QC_bitmap_to_string(query_command->inv_attrs_bitmap);
str2 = QC_bitmap_to_string(query_command->object_type_bitmap);
str3 = WK_to_string(query_command->keytypes_bitmap);
str4 = AT_sources_list_to_string(query_command->sources_list);
sprintf(result_buf, "Query_command : recursive=%d, inv_attrs=%s, k=%d, object_type=%s, sources=%s, (a=%d,g=%d,l=%d,m=%d,t=%d,v=%d,F=%d,L=%d,M=%d,R=%d,S=%d,V=%d), possible keytypes=%s, keys=[%s]\n",
query_command->recursive,
str1,
query_command->k,
str2,
str4,
query_command->a,
query_command->g,
query_command->l,
query_command->m,
query_command->t,
query_command->v,
query_command->F,
query_command->L,
query_command->M,
query_command->R,
query_command->S,
query_command->V,
str3,
query_command->keys);
free(str1);
free(str2);
free(str3);
free(str4);
result = (char *)calloc(1, strlen(result_buf)+1);
strcpy(result, result_buf);
return result;
} /* QC_query_command_to_string() */
/* log_command() */
/*++++++++++++++++++++++++++++++++++++++
Log the command.
This is more to do with Tracing. And should/will get merged with a tracing
module (when it is finalized.)
char *query_str
Query_command *query_command
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
static void log_command(char *query_str, Query_command *query_command) {
/* [<][>][^][v][top][bottom][index][help] */
FILE *logf;
char *str;
if (CO_get_comnd_logging() == 1) {
str = QC_query_command_to_string(query_command);
if (strcmp(CO_get_comnd_logfile(), "stdout") == 0) {
printf("query=[%s]\n%s", query_str, str);
}
else {
logf = fopen(CO_get_comnd_logfile(), "a");
fprintf(logf, "query=[%s]\n%s", query_str, str);
fclose(logf);
}
free(str);
}
} /* log_command() */
/* QC_free() */
/*++++++++++++++++++++++++++++++++++++++
Free the query_command.
Query_command *qc query_command to be freed.
XXX I'm not sure the bitmaps will get freed.
qc->inv_attrs_bitmap
qc->object_type_bitmap
qc->keytypes_bitmap
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
void QC_free(Query_command *qc) {
/* [<][>][^][v][top][bottom][index][help] */
if (qc != NULL) {
if (qc->keys != NULL) {
free(qc->keys);
}
g_list_free(qc->sources_list);
free(qc);
}
} /* QC_free() */
/* QC_new() */
/*++++++++++++++++++++++++++++++++++++++
Create a new query_command.
char *query_str The garden variety whois query string.
int sock The client socket.
Pre-condition: OB_init() must be called before this.
Ie the objects have to be created first.
XXX sock shouldn't be passed here. But it needs to in order to report errors to the client.
Doh!.... this needs some looking into.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
Query_command *QC_new(char *query_str, int sock) {
/* [<][>][^][v][top][bottom][index][help] */
char *my_optarg;
int my_optind;
int c;
int errflg = 0;
char *inv_attrs_str = NULL;
char *object_types_str = NULL;
char *sources_str = NULL;
int opt_argc;
char *opt_argv[MAX_OPT_ARG_C];
char *value;
char *tmp_query_str;
char tmp_query_str_buf[STR_L];
int key_length;
int i;
Query_command *query_command;
int index;
int type;
int attr;
int offset;
char *str;
char str_buf[STR_XL];
query_command = (Query_command *)calloc(1, sizeof(Query_command)+1);
query_command->a = 0;
query_command->g = 0;
query_command->inv_attrs_bitmap = MA_new(MA_END);
query_command->k = 0;
query_command->recursive = 1;
query_command->l = 0;
query_command->m = 0;
/* The 0th source is initialized by default. */
query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(0));
query_command->t = 0;
query_command->v = 0;
query_command->F = 0;
query_command->L = 0;
query_command->M = 0;
query_command->R = 0;
query_command->S = 0;
query_command->object_type_bitmap = MA_new(OBJECT_MASK);
query_command->V = 0;
/*
query_command->keytypes_bitmap = MA_new(MA_END);
*/
query_command->keys = NULL;
my_optind=1;
/* This is so Marek can't crash me :-) */
/* Side Effect - query keys are subsequently cut short to STR_L size. */
/*
tmp_query_str = (char *)calloc(1, strlen(query_str));
strcpy(tmp_query_str, query_str, STR_L);
*/
strncpy(tmp_query_str_buf, query_str, STR_L-1);
tmp_query_str_buf[STR_L-1] = '\0';
opt_argv[0] = NULL;
opt_argv[1] = (char *)strtok(tmp_query_str_buf, " ");
opt_argc = 2;
while ( (opt_argv[opt_argc] = (char *)strtok(NULL, " ")) != NULL ) {
opt_argc++;
/* I really would like to put this statement in the while clause, but
I don't think we can be sure which order it will execute the two
parts in. - So I'll leave it here. */
if ( opt_argc >= MAX_OPT_ARG_C ) break;
}
opt_argv[opt_argc] = NULL;
while ((c = my_getopt(opt_argc, opt_argv, "agi:klrms:t:v:FLMRST:V", &my_optind, &my_optarg)) != EOF) {
switch (c) {
case 'a':
/* The 0th source is initialized already by default. - so don't add it again. */
/* Add the rest of the sources to the list. */
for (i=1; AT_get_source(i) != NULL; i++) {
query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(i));
}
break;
case 'g':
query_command->g=1;
break;
case 'i':
if (my_optarg != NULL) {
inv_attrs_str = my_optarg;
while (*inv_attrs_str) {
index = getsubopt(&inv_attrs_str, AT_get_attributes(), &value);
if (index == -1) {
attr = -1;
strcpy(str_buf, "");
sprintf(str_buf, "Unkown attribute encountered.\n");
SK_puts(sock, str_buf);
errflg++;
}
else {
attr = index/DUP_TOKENS;
if ( MA_isset(OB_get_inv_attr_mask(), attr) == 1 ) {
/* Add the attr to the bitmap. */
MA_set(&(query_command->inv_attrs_bitmap), attr, 1);
}
else {
strcpy(str_buf, "");
sprintf(str_buf, "\"%s\" does not belong to inv_attr.\n", (AT_get_attributes())[index]);
SK_puts(sock, str_buf);
errflg++;
}
}
} /* while () */
} /* if () */
break;
case 'k':
query_command->k = 1;
break;
case 'r':
query_command->recursive = 0;
break;
case 'l':
query_command->l=1;
break;
case 'm':
query_command->m=1;
break;
case 's':
if (my_optarg != NULL) {
sources_str = my_optarg;
/* The 0th source is initialized already by default. - so remove it first. */
query_command->sources_list = g_list_remove(query_command->sources_list, (void *)AT_get_source(0));
while (*sources_str) {
index = getsubopt(&sources_str, AT_get_sources(), &value);
if (index == -1) {
strcpy(str_buf, "");
sprintf(str_buf, "Unkown source encountered.\nNot one of: %s\n", AT_sources_to_string());
SK_puts(sock, str_buf);
errflg++;
}
else {
query_command->sources_list = g_list_append(query_command->sources_list, (void *)AT_get_source(index));
}
} /* while () */
} /* if () */
/*
query_command->s=1;
*/
break;
case 't':
if (my_optarg != NULL) {
object_types_str = my_optarg;
while (*object_types_str) {
index = getsubopt(&object_types_str, AT_get_attributes(), &value);
if (index == -1) {
strcpy(str_buf, "");
sprintf(str_buf, "Unkown object encountered.\n");
SK_puts(sock, str_buf);
errflg++;
}
else {
type = index/DUP_TOKENS;
query_command->t=type;
}
}
}
break;
case 'v':
if (my_optarg != NULL) {
object_types_str = my_optarg;
if (*object_types_str) {
index = getsubopt(&object_types_str, AT_get_attributes(), &value);
if (index == -1) {
strcpy(str_buf, "");
sprintf(str_buf, "Unkown object encountered.\n");
SK_puts(sock, str_buf);
errflg++;
}
else {
type = index/DUP_TOKENS;
query_command->v=type;
}
}
}
break;
case 'F':
query_command->F=1;
break;
case 'L':
query_command->L=1;
break;
case 'M':
query_command->M=1;
break;
case 'R':
query_command->R=1;
break;
case 'S':
query_command->S=1;
break;
case 'T':
/* XXX This is a bit tricky.
The bits are initialized to be all set.
Then each encountered bit is unset.
Finally the result is "not'ed by using XOR with the original. */
if (my_optarg != NULL) {
mask_t tmp = MA_new(OBJECT_MASK);
mask_t original = MA_new(OBJECT_MASK);
object_types_str = my_optarg;
while (*object_types_str) {
index = getsubopt(&object_types_str, AT_get_attributes(), &value);
if (index == -1) {
strcpy(str_buf, "");
sprintf(str_buf, "Unkown attribute encountered.\n");
SK_puts(sock, str_buf);
errflg++;
}
else {
type = index/DUP_TOKENS;
if ( MA_isset(OB_get_object_mask(), type) == 1 ) {
/* Add the type to the bitmap. */
MA_set(&tmp, type, 0);
}
else {
strcpy(str_buf, "");
sprintf(str_buf, "\"%s\" does not belong to object_type.\n", (AT_get_attributes())[index]);
SK_puts(sock, str_buf);
errflg++;
}
}
}
query_command->object_type_bitmap = MA_xor(original, tmp);
MA_free(&original);
MA_free(&tmp);
}
break;
case 'V':
query_command->V=1;
break;
case '?':
errflg++;
break;
default:
errflg++;
}
}
/* XXX Report the error. This could be improved. */
if (opt_argv[my_optind] != NULL) {
if ( (errflg) || (strncmp(opt_argv[my_optind], "-", 1) == 0) ) {
strncpy(str_buf, USAGE, STR_XL-1);
SK_puts(sock, str_buf);
}
}
else {
if (errflg) {
strncpy(str_buf, USAGE, STR_XL-1);
SK_puts(sock, str_buf);
}
}
/* Work out the length of space needed */
key_length = 0;
for (i=my_optind ; i < opt_argc; i++) {
/* length for the string + 1 for the '\0'+ 1 for the ' ' + 1 for good luck. */
if (opt_argv[i] != NULL) {
key_length += strlen(opt_argv[i])+3;
}
}
query_command->keys = (char *)calloc(1, key_length+1);
strcpy(query_command->keys, "");
if (errflg == 0) {
for (i=my_optind; i < opt_argc; i++) {
strcat(query_command->keys, opt_argv[i]);
if ( (i + 1) < opt_argc) {
strcat(query_command->keys, " ");
}
}
} /* XXX - Be careful about where this brace goes. */
/* Now we don't need this anymore */
/*
free(tmp_query_str);
*/
/* Now convert the key to uppercase. */
for (i=0; i <= key_length; i++) {
query_command->keys[i] = toupper(query_command->keys[i]);
}
/* Now make the keytypes_bitmap. */
query_command->keytypes_bitmap = WK_new(query_command->keys);
if ( CO_get_comnd_logging() == 1 ) {
log_command(query_str, query_command);
}
return query_command;
} /* QC_new() */
/* QC_environ_update() */
/*++++++++++++++++++++++++++++++++++++++
Update the query environment.
Return the new environment?
This will include things like setting recursion, and the sources, and other
options deemed to be of an environmental type.
XXX This hasn't been implemented yet. Haven't quite decided what to do here
yet.
(I personally don't like functions that change two things at once, so that
may also be looked into aswell.)
Query_command *qc The query command to be updated.
Query_command *qe The current environment.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
Query_command *QC_environ_update(Query_command *qc, Query_command *qe) {
/* [<][>][^][v][top][bottom][index][help] */
Query_command *query_command;
query_command = (Query_command *)calloc(1, sizeof(Query_command)+1);
query_command->recursive = 1;
return query_command;
} /* QC_environ_update() */