/* * OpenAnonymity * Author: Mathias Kimpl matl@aon.at * Version: * Published under GNU GPL * * THIS FILE IS ONLY FOR DEMONSTRATION PURPOSES - * DOWNLOAD THE LATEST VERSION FROM http://sourceforge.net/projects/openanonymity * * not solved so far: * what happens if end of one bucket (or bb) is " #define DEFAULT_STOP_PATTERN "" #define DEFAULT_OPENANONYMITYXMLFILE_NAME "openanonymity.xml" #define OPANTRUSTMETHOD 0 #define INITIAL_ARRAY_SIZE 20 //Linux dont know strcmpi, but strcasecmp #ifndef Win32 #define strcmpi strcasecmp #endif module AP_MODULE_DECLARE_DATA opan_filter_module; /*___PROTOTYPES_____*/ int searchBucketForConcretePattern(const char*,int,int,char* ); static int searchBucketNew(const char*,int,int,apr_array_header_t*, request_rec *); static apr_xml_elem * getBranch(apr_xml_elem * , char * ,char * ); static apr_status_t fillAnonymizeList(apr_array_header_t * , apr_xml_elem *); static void q_sort(apr_array_header_t * , int , int ); static int isInList(char ,apr_array_header_t * ,int ,int,request_rec * r); /* * This modules per-server configuration structure. */ typedef struct { char *startPattern; char *stopPattern; char *opanXMLFileName; int opanTrustMethod; } open_anonymity_config; /* * holds the Position values of one occurence */ typedef struct { int startPos; int endPos; } patternPos; /*_______GLOBALS_______________*/ static int contentMatchPos; //indicates where a match was made in the content string, TEMPORARY GLOBAL, change it SOON /* * This modules 'brain', to save data till the next processing */ typedef struct open_anonymity_ctx_struct_t { int state; apr_bucket_brigade *bb; //a new bucket brigade apr_array_header_t *directoryAnonymizeList; //Array for the List Items of Tag List in openanonymity.xml apr_array_header_t *posArray; int anyChanges; //indicates that minimum one change is made to bb } open_anonymity_ctx_struct; /* * This function is registered as a handler for HTTP methods and will * therefore be invoked for all GET requests (and others). Regardless * of the request type, this function searches for the pattern in content * and filters data between * */ static apr_status_t mod_open_anonymity_method_handler (ap_filter_t *f, apr_bucket_brigade *bb) { /*__________INIT_PARAMS___________________________________________________________________*/ request_rec *r = f->r; //the request_rec open_anonymity_ctx_struct *ctx = f->ctx; //the context of this module apr_bucket *e; //the current bucket char *beginPattern; //the begin search pattern as defined char *endPattern; //the end search pattern as defined int i; //loop count variable patternPos *currentPos; //holds the current Position of patternPos *tmpPatternPos; //used to went through all Positions int bucketBorder = 0; //indicates that one PATTERN goes over the bucket border const char *ua; //User-Agent Identifier const char *reqFileSrvPath; //the part of the URI after the host: www.opan.org/index.html -> /index.html char *pathTranslated; char *serverPathWithQuery; const char *requestFileName; // the name of the requested File const char * opanFilePath; apr_status_t rv; //Status Var to check errors when opening files etc apr_file_t *fd; //Filepointer to openanonymity.xml file apr_xml_parser *parser; //xml Parser to parse openanonymity.xml apr_xml_doc *doc; //XML Doc apr_xml_elem *linkElement; //XML Element - One Node within the Doc apr_xml_elem *anonymizeList; //XML Element - One Node within the Doc char errbuf[2000]; //Error Buffer String for error messages char errbufXML[2000]; //Error Buffer String for error messages //apr_array_header_t *directoryAnonymizeList; //Array for the List Items of Tag List in openanonymity.xml // apr_array_header_t *fileAnonymizeList; //Array for the List Items of Tag List in openanonymity.xml char ** listElem; //used at different places as a temporary pointer to the list elements // Get the module configuration open_anonymity_config *s_cfg = ap_get_module_config(r->server->module_config, &opan_filter_module); //only for testing, act only on specified browser, otherwise stop open anonymity /* ua = apr_table_get(r->headers_in, "User-Agent"); if (ua && (strncmp(ua, "Opera", 5) == 0)) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } */ /*__________BEGIN_FUNCTIONALITY____________________________________________________________*/ //set the search Pattern as defined either in httpd.conf or by DEFINE beginPattern = s_cfg->startPattern; endPattern = s_cfg->stopPattern; //never been called so far, so init the context if (ctx == NULL) { f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); } //only for the first call within this request //Access the openanonymity.xml file if (ctx->state == 0) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: First entering at this request"); ctx->anyChanges = 0;//Set to 0 for this request ctx->state = 1; //GET REQUEST PARAMETER reqFileSrvPath = r->uri; // "/index.html" //pathInfo = r->parsed_uri.path; //same than reqFileSrvPath pathTranslated= r->filename;//absolute path to requested file //contentType = r->content_type; //r->canonical_filename is the same than pathTranslated //r->parsed_uri.query if (!apr_table_get(r->subprocess_env, "isSpider")) { //Check if Requester is in Spider List (checked with BrowserMatch) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Requester is not in SpiderList"); //COOKIE TEST if(s_cfg->opanTrustMethod == 1){ //If 1, we should check for Cookies. If not, we are finished for this request char *cookies; if ((cookies = apr_table_get(r->headers_in, "Cookie"))) { //then we had already set a cookie ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Cookie is: %s", cookies); //check if cookie is valid if(ap_strstr_c(cookies,"isHuman")) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Checked Cookie, Requester is Human, no anonymizing needed"); ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } } }else{ ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } } /* char cookiebuf[1024]; const char *rname = ap_get_remote_host(f->r->connection, r->per_dir_config,REMOTE_NAME, NULL); apr_snprintf(cookiebuf, sizeof(cookiebuf), "%s.%" APR_TIME_T_FMT, rname, apr_time_now()); new_cookie = apr_psprintf(f->r->pool, "%s=%s; path=/", "OPAN=ID=", cookiebuf); new_cookie = apr_psprintf(f->r->pool, "%s; max-age=%d", new_cookie, 1000); new_cookie = apr_pstrcat(f->r->pool, new_cookie, "; domain=", "localhost", NULL); apr_table_setn(f->r->headers_out,"Set-Cookie", new_cookie); //apr_table_setn(f->r->headers_out,"Set-Cookie", "OPAN=ID=12345678; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=localhost"); //ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Cookie: %s",new_cookie); ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Cookie: %s",apr_table_get(f->r->headers_in, "Cookie")); */ //COOKIE TESTS //Get the Filename of this Path requestFileName = apr_filename_of_pathname(pathTranslated); if(r->parsed_uri.query == NULL){ serverPathWithQuery = apr_pstrcat(f->r->pool,reqFileSrvPath,NULL); } else{ serverPathWithQuery = apr_pstrcat(f->r->pool,reqFileSrvPath,"?",r->parsed_uri.query,NULL); } //Set the end of this path to position before Filename pathTranslated[(strlen(pathTranslated)-strlen(requestFileName))] = '\0'; //READ OPENANONYMITY.XML FILE and BUILD a LIST WITH ALL ANONYM WORDS for this folder //Open File openanonymity.xml for read opanFilePath = apr_pstrcat(f->r->pool,pathTranslated,s_cfg->opanXMLFileName,NULL); ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r," XML FIle path: %s",opanFilePath); rv = apr_file_open(&fd,opanFilePath, APR_WRITE | APR_READ, APR_OS_DEFAULT, f->r->pool); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Could not open xml file, stop executing"); ap_remove_output_filter(f);//remove this filter from the request return ap_pass_brigade(f->next, bb); } //Parse File openanonymity.xml means produce internal representation of xml rv = apr_xml_parse_file(f->r->pool, &parser, &doc, fd, 2000); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Parse error in XML File APR Error: %s XML Error: %s", apr_strerror(rv, errbuf, sizeof(errbuf)), apr_xml_parser_geterror(parser, errbufXML, sizeof(errbufXML))); ap_remove_output_filter(f);//remove this filter from the request return ap_pass_brigade(f->next, bb); } apr_file_close(fd); ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Opan Path and Query %s",serverPathWithQuery); //Get the Config Data of the openanonymity.xml file linkElement = getBranch(doc->root,"link",serverPathWithQuery); if(linkElement == NULL){ //then this Request's URL does not exist in the XML File, stop executing ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Request's URL does not exist in XML File: %s",serverPathWithQuery); ap_remove_output_filter(f);//remove this filter from the request return ap_pass_brigade(f->next, bb); } ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Opan Link Node name %s",linkElement->name); //Get list with all words to anonymize of the Config Data anonymizeList = getBranch(linkElement->parent,"list",""); ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Opan Link Node name %s",anonymizeList->name); //make array for the anonymize words //Type is an array of pointers to Strings(so to char *) ctx->directoryAnonymizeList = apr_array_make(f->r->pool, INITIAL_ARRAY_SIZE, sizeof(char **)); //Fill the Array=List with the data of the xml file rv = fillAnonymizeList(ctx->directoryAnonymizeList,anonymizeList); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Error filling the array data (%d)",rv); } //Insert the Tag into the list of search words listElem = apr_array_push(ctx->directoryAnonymizeList);//get an element *listElem = beginPattern;//store text //Sort the Array q_sort(ctx->directoryAnonymizeList,0,ctx->directoryAnonymizeList->nelts-1); //now i have a sorted array with all Listitems out of the openanonymity.xml file //Unset the content length, because the length already set could be wrong, when we filter //There is no chance to compute the orrect length and to set it before content is sent apr_table_unset(f->r->headers_out, "Content-Length"); //brute force method.................!!!!!! //PHP module does something similar, but header doesnt say Connection: close, //Header from PHP has no Connection String at all apr_table_set(f->r->headers_out, "Connection","close"); //apr_table_unset(f->r->headers_out, "ETag"); //apr_table_unset(f->r->headers_out, "Keep-Alive"); //apr_table_unset(f->r->headers_out, "Accept-Ranges"); //apr_table_unset(f->r->headers_out, "Last-Modified"); //apr_table_set(f->r->headers_out, "Content-Length","855"); }//END if (ctx->state == 0) else{ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"Open Anonymity: Second or more entering at this request"); } //create a new bucket brigade, maybe it is never passed, but it is used temp. ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc); //one bucket seems to be 4194304 Bytes //go through all buckets(e) of this bucket-brigade(bb) APR_BRIGADE_FOREACH(e, bb) { apr_bucket *bucket; //needed when a bucket should be changed, this is the new bucket //apr_bucket **p_bucket; //pointer to bucket, needed for copying const char *data; //holds the bucket data apr_size_t len; //Length of Bucket int matchPos=-1; int searchOffset=0; char ** listElem; //get a new dynamic array from apache, initial size is //INITIAL_ARRAY_SIZE, array holds the Position of all Patterns //destroy it each time a new bucket began ctx->posArray = apr_array_make(f->r->pool, INITIAL_ARRAY_SIZE, sizeof(patternPos)); if (APR_BUCKET_IS_EOS(e)) { //this should work, but it doesnt //APR_BUCKET_REMOVE(e); //APR_BRIGADE_INSERT_TAIL(ctx->bb, e); continue;//EOS is the last bucket, should stop this FOREACH } // read the bucket data apr_bucket_read(e, &data, &len, APR_BLOCK_READ); if(bucketBorder == 1){ matchPos = searchBucketForConcretePattern(data,len,0,endPattern);//search for if(matchPos==-1){//no found -> go to next bucket, throw away this whole bucket //shouldnt happen very often, that there is such big PATTERN continue; //CHECK...what happens with this continue } else{//we found closing bucketBorder = 0;//reset data = &data[matchPos+strlen(endPattern)];//point to char after len = len - matchPos+strlen(endPattern);//recalculate the length of data ctx->anyChanges = 1; // } } //went through this bucket(e) and search for Patterns as well for any anonymous words do{ //matchPos = searchBucket(data,len,searchOffset,beginPattern);//search for matchPos = searchBucketNew(data,len,searchOffset,ctx->directoryAnonymizeList, r);//search for in anonym-list if(matchPos!=-1){//match found listElem = (char **) ctx->directoryAnonymizeList->elts; currentPos = apr_array_push(ctx->posArray);//get new patternPos struct from the array currentPos->startPos = contentMatchPos; //remember Position of this if(strcmp((char *)listElem[matchPos],beginPattern)==0){//we found an Pattern matchPos = searchBucketForConcretePattern(data,len,contentMatchPos+strlen(beginPattern),endPattern);//search for if(matchPos!=-1){// found currentPos->endPos = matchPos + strlen(endPattern);//remember Position of this , but remember the end of it searchOffset=matchPos+strlen(endPattern);//next loop, begin searching on current Pos +1 } else{ //bucket border: we have an open Pattern in this bucket, we should sign this currentPos->endPos = len; bucketBorder = 1; } } else{ //any anonymous word found currentPos->endPos = contentMatchPos + strlen((char *)listElem[matchPos]);//remember Position of this , but remember the end of it searchOffset=contentMatchPos + strlen((char *)listElem[matchPos]);//next loop, begin searching after last match } } } while (matchPos != -1);//do till no more found if(ctx->posArray->nelts > 0){//we had one match minimum //for better processing, add a fixed point at the end in posArray //this Point has same start and endPos currentPos = apr_array_push(ctx->posArray); currentPos->startPos = len;//make both the same value for a clear termination condition currentPos->endPos = len; tmpPatternPos = (patternPos *) ctx->posArray->elts; //list of all posArrays //create a new bucket with data from start to begin of first pattern bucket = apr_bucket_heap_create(data, tmpPatternPos[0].startPos,NULL, f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, bucket);//add it to new bucket brigade //build the new bucket(s) for(i=0;tmpPatternPos[i].endPos != tmpPatternPos[i].startPos;i++){//run through all patternPos in the posArray bucket = apr_bucket_heap_create( &data[tmpPatternPos[i].endPos], //begin data at specified position tmpPatternPos[i+1].startPos-tmpPatternPos[i].endPos,//length NULL, f->c->bucket_alloc); ctx->anyChanges = 1; APR_BRIGADE_INSERT_TAIL(ctx->bb, bucket);//insert into bucket brigade } } else{//we had no PATTERN Match within this bucket //we had no match yet (no single PATTERN), but we have to add this bucket to the new bucket //brigade for the case that we had a match before or later, but we have to do a copy of the //bucket, dont know why (method apr_bucket_copy(e,p_bucket) doesnt work in some cases) bucket = apr_bucket_heap_create(data, len,NULL, f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, bucket); } tmpPatternPos = (patternPos *) ctx->posArray->elts; for(i=0;i<(ctx->posArray->nelts);i++){ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,"",i,tmpPatternPos[i].startPos,tmpPatternPos[i].endPos); } }// END APR_BRIGADE_FOREACH if(ctx->anyChanges == 1){//then we had minimim one match apr_brigade_cleanup(bb); ap_pass_brigade(f->next, ctx->bb); } else{// we had no match, so pass old bb //apr_bucket_destroy(bucket); ap_pass_brigade(f->next, bb); } return APR_SUCCESS; } /* searchBucketForConcretePattern is to search str for the first occurence of pattern, starting * at Position Offset. Because str is not terminated by EOS, also the maximum * length is delivered.It passes back the position when PATTERN was found, * otherwise -1 */ int searchBucketForConcretePattern(const char* str,int len, int searchOffset,char* pattern){ int contentChar; //holds each single character of bucket content int contentCharPreview; //used to make a preview from the current char unsigned int matchCounter=0; //count the matching characters int i=0,j=0,k=0; // loop counter variables int stop = 1; //to leave inner for //go through the whole string by each single character for(i=searchOffset;i=matchCounter){ matchCounter++; } else{ stop=0;//leave this inner for, should try break; } k++; } if(matchCounter == strlen(pattern)){ //then we have found PATTERN, return position return i; } } } return -1; //means pattern not found in whole string } /* searchBucket is to search str for the first occurence of one of the patterns in the array, starting * at Position Offset. Because str is not terminated by EOS, also the maximum * length is delivered.It passes back the position when a PATTERN was found, * otherwise -1 * const char* str: The string to search in * int len: The maximum length to search * int searchOffset: Where to start within str * apr_array_header_t* patternList: An Array with all Search Patterns * request_rec * r: ONLY FOR LOGGING PURPOSES - DELETE */ static int searchBucketNew(const char* str,int bucketLength, int searchOffset,apr_array_header_t* patternList, request_rec * r){ char contentChar; //holds each single character of bucket content char contentCharPreview; //used to make a preview from the current char unsigned int matchCounter=0; //count the matching characters int i=0,j=0,k=0; // loop counter variables int stop = 1; //to leave inner for int isInListval=0; //Position of the match in the anonym-list-array char ** listElem; //One item of the array //go through the whole string str by each single character for(i=searchOffset;ielts; //We have one more char match when we dont get -1. Second Condition is to check if we have a whole word match if(isInListval != -1 && strlen((char *)listElem[isInListval]) > (matchCounter+2)){ matchCounter++; } else{ //maybe we dont found another char-match, maybe we have an exact match stop=0;//leave this inner for, should try break; } k++; } if(isInListval != -1){ //listElem = (char **) patternList->elts; if((matchCounter+2) == strlen((char *)listElem[isInListval])){ //then we have found one whole PATTERN, return position within array contentMatchPos=i; return isInListval; } } } } return -1; //means pattern not found in whole string } /* * This function is a callback and it declares what other functions * should be called for request processing and configuration requests. * This callback function declares the Handlers for other events. */ static void mod_open_anonymity_register_hooks (apr_pool_t *p) { ap_register_output_filter("OPANFILTER", mod_open_anonymity_method_handler,NULL, AP_FTYPE_CONTENT_SET+1); } /** * This function is called when the "OpenAnonymitySearchPatternStart" configuration directive is parsed. */ static const char *set_start_pattern(cmd_parms *parms, void *mconfig, const char *arg) { // get the module configuration (this is the structure created by create_modtut2_config()) open_anonymity_config *s_cfg = ap_get_module_config(parms->server->module_config, &opan_filter_module); // make a duplicate of the argument's value using the command parameters pool. s_cfg->startPattern = (char *) arg; // success return NULL; } /** * This function is called when the "OpenAnonymitySearchPatternStart" configuration directive is parsed. */ static const char *set_xmlFileName(cmd_parms *parms, void *mconfig, const char *arg) { // get the module configuration (this is the structure created by create_modtut2_config()) open_anonymity_config *s_cfg = ap_get_module_config(parms->server->module_config, &opan_filter_module); // make a duplicate of the argument's value using the command parameters pool. s_cfg->opanXMLFileName = (char *) arg; // success return NULL; } /** * This function is called when the "OpenAnonymitySearchPatternStop" configuration directive is parsed. */ static const char *set_stop_pattern(cmd_parms *parms, void *mconfig, const char *arg) { // get the module configuration (this is the structure created by create_modtut2_config()) open_anonymity_config *s_cfg = ap_get_module_config(parms->server->module_config, &opan_filter_module); // make a duplicate of the argument's value using the command parameters pool. s_cfg->stopPattern = (char *) arg; // success return NULL; } /** * This function is called when the configuration directive is parsed. */ static const char *setTrustMethod(cmd_parms *parms, void *mconfig, int on) { // get the module configuration (this is the structure created by create_modtut2_config()) open_anonymity_config *s_cfg = ap_get_module_config(parms->server->module_config, &opan_filter_module); // make a duplicate of the argument's value using the command parameters pool. s_cfg->opanTrustMethod = (int) on; // success return NULL; } /** * A declaration of the configuration directives that are supported by this module. */ static const command_rec mod_open_anonymity_cmds[] = { AP_INIT_TAKE1("OpenAnonymitySearchPatternStart",set_start_pattern,NULL,RSRC_CONF, "OpenAnonymitySearchPatternStart -- the start pattern that tell which data to filter." ), AP_INIT_TAKE1("OpenAnonymityXMLFileName",set_xmlFileName,NULL,RSRC_CONF, "OpenAnonymityXMLFileName -- the changed name of openanonymity.xml, ." ), AP_INIT_TAKE1("OpenAnonymitySearchPatternStop",set_stop_pattern,NULL,RSRC_CONF, "OpenAnonymitySearchPatternStop -- the stop pattern that tells which data to filter." ), AP_INIT_FLAG("OpenAnonymityTrustMethod",setTrustMethod,NULL,RSRC_CONF, "OpenAnonymityTrustMethod on | off -- on...Force Requester to pass a Turing Test, then check for Cookie" ), {NULL} }; /** * Creates the per-server configuration records. */ static void *create_open_anonymity_config(apr_pool_t *p, server_rec *s) { open_anonymity_config *newcfg; // allocate space for the configuration structure from the provided pool p. newcfg = (open_anonymity_config *) apr_pcalloc(p, sizeof(open_anonymity_config)); // set the default value for the search pattern string. newcfg->startPattern = DEFAULT_START_PATTERN; newcfg->stopPattern = DEFAULT_STOP_PATTERN; newcfg->opanXMLFileName = DEFAULT_OPENANONYMITYXMLFILE_NAME; newcfg->opanTrustMethod = OPANTRUSTMETHOD; // return the new server configuration structure. return (void *) newcfg; } /* * Declare and populate the module's data structure. The * name of this structure ('tut1_module') is important - it * must match the name of the module. This structure is the * only "glue" between the httpd core and the module. */ module AP_MODULE_DECLARE_DATA opan_filter_module = { STANDARD20_MODULE_STUFF, // standard stuff; no need to mess with this. NULL, // create per-directory configuration structures - we do not. NULL, // merge per-directory - no need to merge if we are not creating anything. create_open_anonymity_config, // create per-server configuration structures. NULL, // merge per-server - hrm - examples I have been reading don't bother with this for trivial cases. mod_open_anonymity_cmds, // configuration directive handlers mod_open_anonymity_register_hooks, // request handlers }; /* getBranch searches for the occurence of one Node with name nodeName within the tree with root node * Works recursive, breadth first. (Optional it also compares the Text of the Node with nodeText) * apr_xml_elem * node: The Node to start searching * char * nodeName: The name of the searched Node * returns: The Pointer to the found Node */ static apr_xml_elem * getBranch(apr_xml_elem * node, char * nodeName, char * nodeText){ apr_xml_elem *childNode; //Child Nodes of node apr_xml_elem *matchNode; //matchNode, if there is one /* if(strcmp(node->name,nodeName)==0){ //we got it, termination condition only for first node return node; } */ if (node->first_child) { //if node has a child childNode = node->first_child; while (childNode) { if(strcmp(childNode->name,nodeName)==0){ if(strcmp(nodeText,"")!=0){//if we should also check the text if(childNode->first_cdata.first){//check if listitem has cdata if(strcmp(childNode->first_cdata.first->text,nodeText)==0){//if text matches return childNode; } } } else{ return childNode; } } childNode = childNode->next; } //no match on this level, lets get deeper childNode = node->first_child; while (childNode) { matchNode = getBranch(childNode,nodeName,nodeText);//RECURSION //stop directly when a match occurs if(matchNode){ if(strcmp(nodeText,"")!=0){//if we should also check the text if(matchNode->first_cdata.first){//check if listitem has cdata if(strcmp(matchNode->first_cdata.first->text,nodeText)==0){//if text matches return matchNode; } } } else{ return matchNode; } } childNode = childNode->next; } return NULL; } else{ return NULL;//no match } } /* fillAnonymizeList gets a node (name= list) with childnode listitems. * the content of the listitems is written to the array * apr_array_header_t * array: The array to fill * apr_xml_elem * listNode: The Root Node * The structure could look like this * * Kimpl * Mathias * Mathias Kimpl * mathias.kimpl@fh-hagenberg.at * matl@aon.at-neu * rimbert.rudisch@fh-hagenberg.at * */ static apr_status_t fillAnonymizeList(apr_array_header_t * array, apr_xml_elem * listNode ){ apr_xml_elem *childNode; //child Node of listNode, so one listitem const char ** arrayElem; //One Element within the array //termination, when something is wrong if(listNode == NULL) { return -2; } //no node if(strcmp(listNode->name,"list")!=0){ //wrong name of Node return -1; } //go through the listitems if (listNode->first_child) { //if node has a child childNode = listNode->first_child; while (childNode) { if(childNode->first_cdata.first){//check if listitem has cdata arrayElem = apr_array_push(array);//get an element *arrayElem = childNode->first_cdata.first->text; //store text } childNode = childNode->next; //go to next listitem } } return 0; //0...everythings fine } /*sorts the passed array alphabetically * with Quick Sort Algorithm from * http://linux.wku.edu/~lamonml/algor/sort/quick.html */ static void q_sort(apr_array_header_t * array, int left, int right) { int l_hold, r_hold; char * pivot; int pivotInt; const char ** arrayElem; //One Element within the array arrayElem = (char **) array->elts; l_hold = left; r_hold = right; pivot = (char *) arrayElem[left]; while (left < right) { //while ((arrayElem[right] >= pivot) && (left < right)) while ((strcmpi(arrayElem[right],pivot)>=0) && (left < right)) right--; if (left != right) { arrayElem[left] = arrayElem[right]; left++; } //while ((arrayElem[left] <= pivot) && (left < right)) while ((strcmpi(arrayElem[left],pivot)<=0) && (left < right)) left++; if (left != right) { arrayElem[right] = arrayElem[left]; right--; } } arrayElem[left] = pivot; pivotInt = left; left = l_hold; right = r_hold; if (left < pivotInt) q_sort(array, left, pivotInt-1); if (right > pivotInt) q_sort(array, pivotInt+1, right); } //should be extended to an effective search algo /* isInList searches for character ch in the array patternList (anonym-tag-list). It * starts at arrayPos, in that array-element at charPos. If it founds a match, it returns * the matching array Position, otherwise -1 * * ch: the character to look for * * patternList: the array to look at * arrayPos: the specific array position to start search * charPos: The POsition within the specific array-element to start search * r: ONLY FOR LOGGING PURPOSES, DELETE * returns: * -1 ......... no char found * arrayPos.... Position within the array where the next match was found */ static int isInList(char ch,apr_array_header_t * patternList,int arrayPos,int charPos, request_rec * r){ int i; char ** listElem = (char **) patternList->elts; for(i=arrayPos;inelts;i++){ if(listElem[i][charPos] == ch) { return i; } //not found at this position of array, go to next arrayItem, //first check if still the former char is correct e.g Math and Kath, pos a -> Stop if(charPos!=0 && i<(patternList->nelts-1)){ if(listElem[i][charPos-1] != listElem[i+1][charPos-1]){//check if end within this char is reached return -1; } } } return -1; }